Compare commits

...

4 Commits

162
.gitignore vendored

@ -0,0 +1,162 @@
fbconfig.config
*.oo
*.o
*.so.*
*.so
test-ssl
test-tcpclient
test-tcpserver
test-udp
.depend
.Makefile.rules
# ---> Eclipse
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
.project
# ---> C++
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

@ -1,3 +1,10 @@
2023-11-17:
- TCP::WebGetFile timeout increased to 20000ms and added another function including an timeout parameter.
2022-02-02:
- TCP::WebGetFile downloaading from web is working fine now.
- TCP constructor is dealing better on windows now. WinSock is Hell.
2020-10-18: 2020-10-18:
- needed to disable ipv6 on windows for the moment, as long as i can't - needed to disable ipv6 on windows for the moment, as long as i can't
get both ipv4 and ipv6 to work at the same time. get both ipv4 and ipv6 to work at the same time.

@ -1,5 +1,5 @@
.SILENT: help .SILENT: help
VERSION=0.1 VERSION=0.2
OBJLIB_NAME=UDPTCPNetwork OBJLIB_NAME=UDPTCPNetwork
-include Makefile.rules -include Makefile.rules
@ -48,7 +48,7 @@ keygen:
install: $(TARGET) install: $(TARGET)
cp -f $(TARGET) $(PREFIX)/lib/ cp -f $(TARGET) $(PREFIX)/lib/
if test -f "lib$(OBJLIB_NAME).so"; then cp -f lib$(OBJLIB_NAME).so $(PREFIX)/lib/ ; fi if test -f "lib$(OBJLIB_NAME).so"; then cp -a -f --preserve=links lib$(OBJLIB_NAME).so $(PREFIX)/lib/ ; fi
cp -f UDPTCPNetwork.h $(PREFIX)/include/ cp -f UDPTCPNetwork.h $(PREFIX)/include/
uninstall: uninstall:

@ -106,12 +106,13 @@ class TCP {
private: private:
SOCKET sock; SOCKET sock;
struct sockaddr_storage peeraddr; struct sockaddr_storage peeraddr;
string remote_host; string remote_host;
string remote_port; string remote_port;
int readcnt; int readcnt;
int writecnt; int writecnt;
int islisten; int islisten;
int WebHeaderGetParamValue(std::string line, std::string *parm, std::string *value);
public: public:
TCP(); TCP();
TCP(SOCKET s); TCP(SOCKET s);
@ -140,10 +141,9 @@ public:
const string GetRemoteAddr(); const string GetRemoteAddr();
const string GetLocalAddr(); const string GetLocalAddr();
const string WebGetURLHost (string url); int WebGetURLElements (string url, string *host, string *port, string *file);
const string WebGetURLPort (string url); int WebGetFile (string url, char *buffer, int maxsize, char *formdata);
const string WebGetURLFile (string url); int WebGetFile (string url, char *buffer, int maxsize, char *formdata, int timeout_ms);
int WebGetFile (string url, char *buffer, int maxsize);
}; };

333
tcp.cc

@ -1,21 +1,48 @@
/* /////////////////////////////////////////////////////////////////////////////////
* //
*/ // tcp.cc is part of TestModbus-Server.
//
/////////////////////////////////////////////////////////////////////////////////
#include "UDPTCPNetwork.h"
#include <stdio.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 <stdlib.h>
#include <string.h> /* memset() */ #include <string.h> /* memset() */
#include <errno.h> #include <errno.h>
#include "UDPTCPNetwork.h" using namespace std;
int __tcpinit__ = 0;
TCP::~TCP() { TCP::~TCP() {
Close(); Close();
} }
TCP::TCP() { 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; sock = 0;
writecnt = 0; writecnt = 0;
readcnt = 0; readcnt = 0;
@ -98,12 +125,10 @@ int TCP::Listen(int port) {
TCP* TCP::Accept() { TCP* TCP::Accept() {
fd_set rfds; fd_set rfds;
struct timeval tv; struct timeval tv;
int retval, err, i; int retval;
SOCKET newsock; SOCKET newsock;
struct sockaddr_storage cliaddr; struct sockaddr_storage cliaddr;
socklen_t cliaddr_len = sizeof(struct sockaddr_storage); socklen_t cliaddr_len = sizeof(struct sockaddr_storage);
char host[NET_BUFFERSIZE];
char port[NET_BUFFERSIZE];
TCP *tcp = NULL; TCP *tcp = NULL;
if (sock <= 0) return NULL; if (sock <= 0) return NULL;
@ -137,8 +162,6 @@ TCP* TCP::Accept() {
int TCP::Connect(string h, string p) { int TCP::Connect(string h, string p) {
int i = 0;
remote_host = h; remote_host = h;
remote_port = p; remote_port = p;
@ -163,7 +186,7 @@ int TCP::Connect(string hostport, int defaultport) {
int TCP::Connect() { int TCP::Connect() {
int err, s; int err, s = 0;
struct addrinfo hints, *res, *rp; struct addrinfo hints, *res, *rp;
struct timeval timeout; struct timeval timeout;
@ -175,7 +198,7 @@ int TCP::Connect() {
err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res); err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res);
if (err != 0) { 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; return 0;
} }
@ -340,53 +363,178 @@ 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) {
return WebGetFile(url, buffer, maxsize, formdata, 20000);
}
int TCP::WebGetFile (string url, char *buffer, int maxsize, char *formdata, int timeout_ms) {
char outdata[NET_BUFFERSIZE]; char outdata[NET_BUFFERSIZE];
char indata[NET_BUFFERSIZE]; char indata[NET_BUFFERSIZE];
char host[NET_HOSTLEN]; string host, port, file;
char port[NET_PORTLEN]; int len, line_cnt, i, buffpos = 0, c;
int breakup, len, head, i, buffpos = 0; 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()) { if (!IsConnected()) {
strncpy (host, WebGetURLHost (url).c_str(), NET_HOSTLEN);
strncpy (port, WebGetURLPort (url).c_str(), NET_PORTLEN);
Connect (host, port); Connect (host, port);
} }
if (!IsConnected()) return -1; if (!IsConnected()) return -1;
//
// send http request // 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)); Write (outdata, strlen (outdata));
// wait for data start //
i = breakup = 0; // read header
head = 1; //
while (!breakup && head && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) { indata[0] = '\0';
indata[len] = 0; len = ReadTimeout (indata, NET_BUFFERSIZE-1, timeout_ms);
while (i < len -4 && head && !breakup) { if (len <= 0) {
if (indata[i] == 0x0d && indata [i+1] == 0x0a && indata [i+2] == 0x0d && indata [i+3] == 0x0a) { fprintf (stderr, "%s:%d reading header Error:%s\n", __FILE__, __LINE__, strerror(errno));
head = 0; return -1;
i = i + 4; }
buffpos = len-i; indata[len] = 0;
if (buffpos > maxsize) buffpos = maxsize;
memcpy (buffer, indata+i, buffpos); //
// 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
} }
else if (strncmp (indata+i, "Content-Length:", 15) == 0) { //
i = i + 16; // 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, "403 ", 4) == 0) breakup = 1; //
else i++; // 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;
}
//
// 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]);
}
}
//
// 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;
// read data while ((len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) > 0) {
while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
i = len; i = len;
if (i > maxsize-buffpos) i = maxsize-buffpos; if (i > maxsize-buffpos) i = maxsize-buffpos;
if (i > 0) { if (i > 0) {
if (chunked_transfer) {
if (i > chunked_bytes) i = chunked_bytes;
chunked_bytes -= i;
}
memcpy (buffer+buffpos, indata, i); memcpy (buffer+buffpos, indata, i);
buffpos += i; buffpos += i;
} }
@ -395,46 +543,87 @@ int TCP::WebGetFile (string url, char *buffer, int maxsize) {
return buffpos; 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) { for (i = 0; i < 5; i++) url[i] = toupper(url[i]);
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";
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) { for (step = _WEBGET_URL_SERVER;curpos < (int)url.length(); curpos++) {
string result; if (step == _WEBGET_URL_SERVER) {
int posEServPort = 0; // end Server:Port 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); if (host != NULL) *host = h;
result = url.substr (posEServPort); if (file != NULL) *file = f;
if (port != NULL) *port = p;
return result; return retval;
}; };

Loading…
Cancel
Save