ViaThinkSoft CodeLib
This article is in:
CodeLib → Programming aids → C / C++
Verworfener Code. Ersetzt durch LibCURL Variante.
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> // sockaddr_in
#include <netdb.h> // gethostbyname(), hostent
#include <signal.h>
#include <stdexcept>
//********************************************************************************************
//
// http_callUrl
//
// Teilt eine URL (Form: http://www.example.com/dir/script.ext?querystring) in ihre Bestandteile und übergibt diese an http_call
std::runtime_error CreateSocketError()
{
std::ostringstream temp;
#ifdef linux
temp << "Socket-Fehler #" << errno << ": " << strerror(errno);
#else
int error = WSAGetLastError();
temp << "Socket-Fehler #" << error;
char* msg;
if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<char*>(&msg), 0, NULL))
{
try
{
temp << ": " << msg;
LocalFree(msg);
}
catch(...)
{
LocalFree(msg);
throw;
}
}
#endif
return std::runtime_error(temp.str());
}
// Liest eine Zeile des Sockets in einen stringstream
void GetLine(int socket, std::stringstream& line)
{
for(char c; recv(socket, &c, 1, 0) > 0; line << c)
{
if(c == '\n')
{
return;
}
}
throw CreateSocketError();
}
// TODO: Wird HTTP:// und http:// berücksichtigt? (protokoll ist case insensitive)
bool http_callUrl (string url) {
logEvent(VERBOSE_LEVEL_DEBUG, "callURL: " + url);
string server = "";
unsigned int port;
bool use_ssl;
string request = "GET / HTTP/1.1";
// http:// suchen und löschen
// find_first_of() war falsch. dort wurde nur nach EINEM der zeichen gesucht, nicht nach der kombination
if (url.find("http://") == 0) {
url = url.substr(7, url.length() - 7);
use_ssl = false;
port = 80; // Standard-Port
} else if (url.find("https://") == 0) {
url = url.substr(8, url.length() - 8);
use_ssl = true;
port = 443; // Standard-Port
} else {
logEvent(VERBOSE_LEVEL_ERROR, "Invalid URL - Protocol unknown or not given: " + url);
return false;
}
// Slash finden und String splitten
int slashPos = url.find_first_of("/");
if (slashPos >= 0) {
server = url.substr(0, slashPos);
request = "GET " + url.substr(slashPos, url.length() - slashPos) + " HTTP/1.1";
} else
server = url;
// Doppelpunkt finden und String splitten
int colonPos = server.find_first_of(":");
if (colonPos >= 0) {
port = StrToInt(server.substr(colonPos + 1, server.length() - colonPos - 1));
server = url.substr(0, colonPos);
}
if (server == "") {
logEvent(VERBOSE_LEVEL_WARNING, "No server address given.");
return false;
} else {
request += "\r\n";
request += "Host: ";
request += server;
}
request += "\r\n";
request += "User-Agent: ";
request += USER_AGENT;
request += "\r\n";
request += "Connection: close";
request += "\r\n\r\n";
logEvent(VERBOSE_LEVEL_DEBUG, "callURL: goto http_call with SERVER = " + server + " PORT = " + IntToStr(port) + " REQUEST = " + request);
return http_call(server, port, request, use_ssl);
}
//********************************************************************************************
//
// http_call
//
// Ruft eine HTTP-Webseite auf und liefert den Erfolgswert zurück
// TODO: Fehlercodes beachten, nicht nur Socketfehler berücksichtigen
// TODO: Umleitungen beachten (absolute und relative 30x-Adressangaben)
// TODO: Korrekt mit SSL umgehen
// TODO: User-Agent an Server senden
// TODO: Ausgabe korrekt parsen und zurückgeben
bool http_call(string server, unsigned int port, string request, bool use_ssl) {
logEvent(VERBOSE_LEVEL_DEBUG, "Call URL: http://" + server + ":" + IntToStr(port) + "/ - REQUEST: " + request);
// Establish connection to server
hostent* phe = gethostbyname(server.c_str());
if(phe == NULL) {
logEvent(VERBOSE_LEVEL_WARNING, "Could not resolve hostname " + server + "!");
return false;
}
if(phe->h_addrtype != AF_INET) {
logEvent(VERBOSE_LEVEL_ERROR, "Invalid address type!");
return false;
}
if(phe->h_length != 4) {
logEvent(VERBOSE_LEVEL_ERROR, "Invalid address type!");
return false;
}
// TODO: Auch SSL-Sockets unterstützen!! (Pflicht beim WebBase-Secure-Mode)
int Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(Socket == -1) {
logEvent(VERBOSE_LEVEL_ERROR, "Could not establish socket!");
return false;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_port = htons(port); // Das HTTP-Protokoll benutzt Port 80
char** p = phe->h_addr_list; // p mit erstem Listenelement initialisieren
int result; // Ergebnis von connect
do
{
if(*p == NULL) // Ende der Liste
{
logEvent(VERBOSE_LEVEL_ERROR, "Could not establish connection to server " + server + "!");
return false;
}
service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p);
p++;
result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service));
logEvent(VERBOSE_LEVEL_DEBUG, "Server " + server + ": New connection try - result = " + IntToStr(result));
}
while(result == -1);
logEvent(VERBOSE_LEVEL_DEBUG, "Connection to server " + server + " on port " + IntToStr(port) + " established!");
// Send HTTP request
int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
do
{
int result = send(Socket, request.c_str() + bytesSent, request.size() - bytesSent, 0);
logEvent(VERBOSE_LEVEL_DEBUG, "Server " + server + ": HTTP result = " + IntToStr(result));
if (result < 0) { // Wenn send einen Wert < 0 zurück gibt deutet dies auf einen Fehler hin.
logEvent(VERBOSE_LEVEL_ERROR, "Socket error #" + IntToStr(errno) + ": " + strerror(errno));
return false;
}
bytesSent += result;
} while(bytesSent < request.size());
// Return true
while(true)
{
stringstream line;
try
{
GetLine(Socket, line);
}
catch(exception& e) // Ein Fehler oder Verbindungsabbruch
{
break; // Schleife verlassen
}
logEvent(VERBOSE_LEVEL_DEBUG, "Ausgabe: " + line.str());
}
logEvent(VERBOSE_LEVEL_DEBUG, "HTTP call successful!");
close(Socket);
return true;
}
Daniel Marschall
ViaThinkSoft Co-Founder
ViaThinkSoft Co-Founder