|
|
|
@ -1,21 +1,48 @@
|
|
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// tcp.cc is part of TestModbus-Server.
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
#include "UDPTCPNetwork.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <unistd.h> /* close() */
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
|
|
|
|
#else
|
|
|
|
|
#include <unistd.h> /* close() */
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h> /* memset() */
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include "UDPTCPNetwork.h"
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
int __tcpinit__ = 0;
|
|
|
|
|
|
|
|
|
|
TCP::~TCP() {
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TCP::TCP() {
|
|
|
|
|
UDPTCPNetwork();
|
|
|
|
|
if (__tcpinit__ == 0) {
|
|
|
|
|
#ifdef BUILD_WINDOWS
|
|
|
|
|
|
|
|
|
|
WORD wVersionRequested;
|
|
|
|
|
WSADATA wsaData;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
|
|
|
|
|
wVersionRequested = MAKEWORD(2, 2);
|
|
|
|
|
|
|
|
|
|
err = WSAStartup(wVersionRequested, &wsaData);
|
|
|
|
|
if (err != 0) {
|
|
|
|
|
/* Tell the user that we could not find a usable */
|
|
|
|
|
/* Winsock DLL. */
|
|
|
|
|
printf("WSAStartup failed with error: %d\n", err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
__tcpinit__ = 1;
|
|
|
|
|
}
|
|
|
|
|
sock = 0;
|
|
|
|
|
writecnt = 0;
|
|
|
|
|
readcnt = 0;
|
|
|
|
@ -98,12 +125,10 @@ int TCP::Listen(int port) {
|
|
|
|
|
TCP* TCP::Accept() {
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
int retval, err, i;
|
|
|
|
|
int retval;
|
|
|
|
|
SOCKET newsock;
|
|
|
|
|
struct sockaddr_storage cliaddr;
|
|
|
|
|
socklen_t cliaddr_len = sizeof(struct sockaddr_storage);
|
|
|
|
|
char host[NET_BUFFERSIZE];
|
|
|
|
|
char port[NET_BUFFERSIZE];
|
|
|
|
|
TCP *tcp = NULL;
|
|
|
|
|
|
|
|
|
|
if (sock <= 0) return NULL;
|
|
|
|
@ -137,8 +162,6 @@ TCP* TCP::Accept() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int TCP::Connect(string h, string p) {
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
remote_host = h;
|
|
|
|
|
remote_port = p;
|
|
|
|
|
|
|
|
|
@ -163,7 +186,7 @@ int TCP::Connect(string hostport, int defaultport) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int TCP::Connect() {
|
|
|
|
|
int err, s;
|
|
|
|
|
int err, s = 0;
|
|
|
|
|
struct addrinfo hints, *res, *rp;
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
|
|
|
|
@ -175,7 +198,7 @@ int TCP::Connect() {
|
|
|
|
|
|
|
|
|
|
err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res);
|
|
|
|
|
if (err != 0) {
|
|
|
|
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
|
|
|
|
|
fprintf(stderr, "getaddrinfo: Host:'%s' Port:'%s' Error:%s\n", remote_host.c_str(), remote_port.c_str(), gai_strerror(err));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -340,53 +363,174 @@ int TCP::IsData(int timeout) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int TCP::WebGetFile (string url, char *buffer, int maxsize) {
|
|
|
|
|
/*
|
|
|
|
|
* Read a single line and split in parameter and value
|
|
|
|
|
* if value and parm is set to NULL this field will not be set
|
|
|
|
|
*/
|
|
|
|
|
int TCP::WebHeaderGetParamValue(std::string line, std::string *parm, std::string *value) {
|
|
|
|
|
size_t pos = line.find(" ");
|
|
|
|
|
if (pos == std::string::npos) {
|
|
|
|
|
fprintf (stderr, "%s error with protocol. HTTP/ without space? Line:'%s'\n",
|
|
|
|
|
__FUNCTION__, line.c_str());
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parm != NULL) *parm = line.substr (0, pos);
|
|
|
|
|
if (value != NULL) *value = line.substr (pos+1, std::string::npos);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* read any data from server
|
|
|
|
|
* Return Value:
|
|
|
|
|
* on error: -1
|
|
|
|
|
* success : size of buffer
|
|
|
|
|
*/
|
|
|
|
|
int TCP::WebGetFile (string url, char *buffer, int maxsize, char *formdata) {
|
|
|
|
|
char outdata[NET_BUFFERSIZE];
|
|
|
|
|
char indata[NET_BUFFERSIZE];
|
|
|
|
|
char host[NET_HOSTLEN];
|
|
|
|
|
char port[NET_PORTLEN];
|
|
|
|
|
int breakup, len, head, i, buffpos = 0;
|
|
|
|
|
|
|
|
|
|
string host, port, file;
|
|
|
|
|
int len, line_cnt, i, buffpos = 0, c;
|
|
|
|
|
string protocol = "";
|
|
|
|
|
string type = "";
|
|
|
|
|
string line = "";
|
|
|
|
|
string lineUP = "";
|
|
|
|
|
string status = "";
|
|
|
|
|
int chunked_transfer = 0;
|
|
|
|
|
int chunked_bytes = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// clear input buffer
|
|
|
|
|
if (buffer == NULL) return -1;
|
|
|
|
|
buffer[0] = '\0';
|
|
|
|
|
|
|
|
|
|
WebGetURLElements(url, &host, &port, &file);
|
|
|
|
|
if (!IsConnected()) {
|
|
|
|
|
strncpy (host, WebGetURLHost (url).c_str(), NET_HOSTLEN);
|
|
|
|
|
strncpy (port, WebGetURLPort (url).c_str(), NET_PORTLEN);
|
|
|
|
|
Connect (host, port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IsConnected()) return -1;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// send http request
|
|
|
|
|
snprintf (outdata, NET_BUFFERSIZE, "GET %s HTTP/1.0\nUser-Agent: tcpclient \nHost: %s\n\n", WebGetURLFile (url).c_str(), host);
|
|
|
|
|
//
|
|
|
|
|
if (formdata == NULL)
|
|
|
|
|
snprintf (outdata, NET_BUFFERSIZE, "GET %s HTTP/1.0\r\nUser-Agent: unknown\r\nHost: %s\r\nAccept:*.*\r\n\r\n", file.c_str(), host.c_str());
|
|
|
|
|
else
|
|
|
|
|
snprintf (outdata, NET_BUFFERSIZE, "POST %s HTTP/1.1\r\nUser-Agent: unknown\r\nHost: %s\r\nContent-Length: %ld\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept:*.*\r\n\r\n%s\r\n",
|
|
|
|
|
file.c_str(), host.c_str(), strlen (formdata), formdata);
|
|
|
|
|
Write (outdata, strlen (outdata));
|
|
|
|
|
|
|
|
|
|
// wait for data start
|
|
|
|
|
i = breakup = 0;
|
|
|
|
|
head = 1;
|
|
|
|
|
while (!breakup && head && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
|
|
|
|
indata[len] = 0;
|
|
|
|
|
while (i < len -4 && head && !breakup) {
|
|
|
|
|
if (indata[i] == 0x0d && indata [i+1] == 0x0a && indata [i+2] == 0x0d && indata [i+3] == 0x0a) {
|
|
|
|
|
head = 0;
|
|
|
|
|
i = i + 4;
|
|
|
|
|
buffpos = len-i;
|
|
|
|
|
if (buffpos > maxsize) buffpos = maxsize;
|
|
|
|
|
memcpy (buffer, indata+i, buffpos);
|
|
|
|
|
//
|
|
|
|
|
// read header
|
|
|
|
|
//
|
|
|
|
|
indata[0] = '\0';
|
|
|
|
|
len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000);
|
|
|
|
|
if (len <= 0) {
|
|
|
|
|
fprintf (stderr, "%s:%d reading header Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
indata[len] = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// read all lines until an empty line is reached
|
|
|
|
|
for (line = "", lineUP = "", line_cnt = 0, i = 0; i < len; i++) {
|
|
|
|
|
if (indata[i] == '\n' || indata[i] == '\r') {
|
|
|
|
|
if (i < len && (indata[i+1] == '\n' || indata[i+1] == '\r')) i++;
|
|
|
|
|
|
|
|
|
|
if (line.length() == 0) {
|
|
|
|
|
i++;
|
|
|
|
|
break; // break loop, read data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HTTP Header
|
|
|
|
|
else if (lineUP.find ("HTTP/") == 0) {
|
|
|
|
|
if (WebHeaderGetParamValue(line, &protocol, &status) < 0) {
|
|
|
|
|
fprintf (stderr, "%s:%d reading header Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp (indata+i, "Content-Length:", 15) == 0) {
|
|
|
|
|
i = i + 16;
|
|
|
|
|
//
|
|
|
|
|
// Transfer Encoding
|
|
|
|
|
else if (lineUP.find ("TRANSFER-ENCODING:") == 0) {
|
|
|
|
|
std::string temp;
|
|
|
|
|
if (WebHeaderGetParamValue(line, NULL, &temp) < 0) {
|
|
|
|
|
fprintf (stderr, "%s:%d reading header Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
for (int j = 0; (long int)j < (long int) temp.length(); j++)
|
|
|
|
|
temp[i] = toupper(temp[i]);
|
|
|
|
|
if (temp.find("chunked") != std::string::npos) chunked_transfer = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp (indata+i, "403 ", 4) == 0) breakup = 1;
|
|
|
|
|
else i++;
|
|
|
|
|
//
|
|
|
|
|
// type of file
|
|
|
|
|
else if (lineUP.find ("CONTENT-TYPE:") == 0) {
|
|
|
|
|
if (WebHeaderGetParamValue(line, NULL, &type) < 0) {
|
|
|
|
|
fprintf (stderr, "%s:%d reading header Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lineUP = line = "";
|
|
|
|
|
line_cnt++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
line += indata[i];
|
|
|
|
|
lineUP += toupper(indata[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read data
|
|
|
|
|
while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
|
|
|
|
//
|
|
|
|
|
// chunked data?
|
|
|
|
|
// size we need to load
|
|
|
|
|
if (chunked_transfer) {
|
|
|
|
|
int v;
|
|
|
|
|
for (v = 0, line_cnt = 0; i < len; i++) {
|
|
|
|
|
if (indata[i] == '\r' || indata[i] == '\n') {
|
|
|
|
|
i++;
|
|
|
|
|
if (i < len && (indata[i] == '\n' || indata[i] == '\r')) i++;
|
|
|
|
|
chunked_bytes = v;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v = v << 4;
|
|
|
|
|
indata[i] = tolower(indata[i]);
|
|
|
|
|
if (indata[i] >= '0' && indata[i] <= '9') v += (indata[i] - '0');
|
|
|
|
|
else if (indata[i] >= 'a' && indata[i] <= 'f') v += (10 + indata[i] - 'a');
|
|
|
|
|
else {
|
|
|
|
|
fprintf (stderr, "%s:%d reading chunk bytes, invalid HEX code indata:'%s'\n", __FILE__, __LINE__, indata);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// check bytes to read, and remove these from chunked_bytes
|
|
|
|
|
if (chunked_bytes < len-i) c = chunked_bytes;
|
|
|
|
|
else c = len-i;
|
|
|
|
|
chunked_bytes -= c;
|
|
|
|
|
}
|
|
|
|
|
else c = len-i;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// read data, but first copy the left over bytes into the output buffer
|
|
|
|
|
if (c > 0) memcpy (buffer, indata+i, c);
|
|
|
|
|
buffpos = c;
|
|
|
|
|
|
|
|
|
|
while ((len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) > 0) {
|
|
|
|
|
i = len;
|
|
|
|
|
if (i > maxsize-buffpos) i = maxsize-buffpos;
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
if (chunked_transfer) {
|
|
|
|
|
if (i > chunked_bytes) i = chunked_bytes;
|
|
|
|
|
chunked_bytes -= i;
|
|
|
|
|
}
|
|
|
|
|
memcpy (buffer+buffpos, indata, i);
|
|
|
|
|
buffpos += i;
|
|
|
|
|
}
|
|
|
|
@ -395,46 +539,87 @@ int TCP::WebGetFile (string url, char *buffer, int maxsize) {
|
|
|
|
|
return buffpos;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const string TCP::WebGetURLHost (string url) {
|
|
|
|
|
string result;
|
|
|
|
|
int posSServPort = 7; // begin server:port
|
|
|
|
|
int posEServPort = 0; // end Server:Port
|
|
|
|
|
int posPort = -1; // port Position
|
|
|
|
|
|
|
|
|
|
posEServPort = url.find("/", 7);
|
|
|
|
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
|
|
|
|
posPort = result.find(":");
|
|
|
|
|
if (posPort > 0)
|
|
|
|
|
result = url.substr (posSServPort, posPort);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
// FIXME: everything below here is wrong...
|
|
|
|
|
/*
|
|
|
|
|
* fills the elements and returns 0 on success. Returns set bits if value was found
|
|
|
|
|
* 1 ... hostname
|
|
|
|
|
* 2 ... port
|
|
|
|
|
* 3 ... file
|
|
|
|
|
*/
|
|
|
|
|
enum _webgeturl_step_ {
|
|
|
|
|
_WEBGET_URL_PROTO = 0,
|
|
|
|
|
_WEBGET_URL_SERVER,
|
|
|
|
|
_WEBGET_URL_PORT,
|
|
|
|
|
_WEBGET_URL_FILE
|
|
|
|
|
};
|
|
|
|
|
int TCP::WebGetURLElements (string url, string *host, string *port, string *file) {
|
|
|
|
|
string h = "";
|
|
|
|
|
string p = "";
|
|
|
|
|
string f = "/";
|
|
|
|
|
const string prefix1 = "HTTP://";
|
|
|
|
|
const string prefix2 = "HTTPS://";
|
|
|
|
|
int retval = 0;
|
|
|
|
|
int i;
|
|
|
|
|
int curpos = 0;
|
|
|
|
|
int step = _WEBGET_URL_PROTO;
|
|
|
|
|
|
|
|
|
|
const string TCP::WebGetURLPort (string url) {
|
|
|
|
|
string result;
|
|
|
|
|
int posSServPort = 7; // begin server:port
|
|
|
|
|
int posEServPort = 0; // end Server:Port
|
|
|
|
|
int posPort = -1; // port Position
|
|
|
|
|
|
|
|
|
|
posEServPort = url.find("/", 7);
|
|
|
|
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
|
|
|
|
posPort = result.find(":");
|
|
|
|
|
if (posPort > 0)
|
|
|
|
|
result = result.substr (posPort+1);
|
|
|
|
|
else
|
|
|
|
|
result = "80";
|
|
|
|
|
for (i = 0; i < 5; i++) url[i] = toupper(url[i]);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
//
|
|
|
|
|
// try to find the protocol and //
|
|
|
|
|
if (url.find(prefix1) == 0) {
|
|
|
|
|
retval |= 2;
|
|
|
|
|
p = "80";
|
|
|
|
|
curpos = prefix1.length();
|
|
|
|
|
}
|
|
|
|
|
else if (url.find(prefix2) == 0) {
|
|
|
|
|
retval |= 2;
|
|
|
|
|
p = "443";
|
|
|
|
|
curpos = prefix2.length();
|
|
|
|
|
// FIXME: SSL needs to be implemented
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (url.find ("//") != std::string::npos) {
|
|
|
|
|
errno = EPROTONOSUPPORT;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else curpos = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const string TCP::WebGetURLFile (string url) {
|
|
|
|
|
string result;
|
|
|
|
|
int posEServPort = 0; // end Server:Port
|
|
|
|
|
for (step = _WEBGET_URL_SERVER;curpos < (int)url.length(); curpos++) {
|
|
|
|
|
if (step == _WEBGET_URL_SERVER) {
|
|
|
|
|
if (url[curpos] == '/') step = _WEBGET_URL_FILE;
|
|
|
|
|
else if (url[curpos] == ':') {
|
|
|
|
|
step = _WEBGET_URL_PORT;
|
|
|
|
|
p = "";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
h += url[curpos];
|
|
|
|
|
retval |= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (step == _WEBGET_URL_PORT) {
|
|
|
|
|
if (url[curpos] == '/') step = _WEBGET_URL_FILE;
|
|
|
|
|
else {
|
|
|
|
|
p += url[curpos];
|
|
|
|
|
retval |= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (step == _WEBGET_URL_FILE) {
|
|
|
|
|
f += url[curpos];
|
|
|
|
|
retval |= 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
posEServPort = url.find("/", 7);
|
|
|
|
|
result = url.substr (posEServPort);
|
|
|
|
|
if (host != NULL) *host = h;
|
|
|
|
|
if (file != NULL) *file = f;
|
|
|
|
|
if (port != NULL) *port = p;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
return retval;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|