diff --git a/Makefile b/Makefile index 2258722..0bea834 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CXX=g++ CXXFLAGS= -Wall -ggdb -g -std=c++11 -I/usr/include/libxml2 -LDFLAGS= -lm -L/usr/local/lib -g -ggdb -lxml2 -lcrypto +LDFLAGS= -lm -L/usr/local/lib -g -ggdb -lxml2 -lcrypto -lUDPTCPNetwork APPS = fbsh-cli @@ -14,7 +14,7 @@ all: $(APPS) $(CXX) -o $@ -c $(CXXFLAGS) $< # $(CXX) -o $@ $^ $(LDFLAGS) -L./ -I./ -ltinfo -lncursesw -fbsh-cli: fbsh.oo cfg.oo fbsh-cli.oo tcp.oo +fbsh-cli: fbsh.oo cfg.oo fbsh-cli.oo $(CXX) -o $@ $^ $(LDFLAGS) -L./ -I./ clean: diff --git a/fbsh.cc b/fbsh.cc index 74e9c35..191717f 100644 --- a/fbsh.cc +++ b/fbsh.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include "fbsh.h" diff --git a/fbsh.h b/fbsh.h index 8b830f7..ac03669 100644 --- a/fbsh.h +++ b/fbsh.h @@ -9,8 +9,7 @@ #include #include #include - -#include "tcp.h" +#include std::string generateMD5 (char* input, int size); diff --git a/tcp.cc b/tcp.cc deleted file mode 100644 index 91a8c52..0000000 --- a/tcp.cc +++ /dev/null @@ -1,679 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// tcp.cc is part of TestModbus-Server. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "tcp.h" -#include -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) -#else - #include /* close() */ -#endif -#include -#include /* memset() */ -#include - -using namespace std; - -int tcpinit; -// -// convert host and port to sockaddr_in6 -// -int dns_filladdr (string host, string port, int ai_family, struct sockaddr_storage *sAddr) { - struct addrinfo hints, *res; - int err; - - bzero (&hints, sizeof (struct addrinfo)); - hints.ai_family = ai_family; - hints.ai_socktype = SOCK_DGRAM; - - if ((err = getaddrinfo (host.c_str(), port.c_str(), &hints, &res)) < 0) { - fprintf (stdout, "dns_filladdr (getaddrinfo):%s\n", gai_strerror (err)); - return -1; - } - - memcpy (sAddr, res->ai_addr, res->ai_addrlen); - freeaddrinfo (res); - - return 1; -}; - - -// -// convert int to char* -// -char* itoa(char* buffer, int number, int size) { - snprintf (buffer, size, "%d", number); - return buffer; -} - - -TCP::~TCP() { - Close(); -} - -TCP::TCP() { - 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; - islisten = 0; -}; - -TCP::TCP(int s) { - TCP(); - sock = s; -// memset (&localaddr, 0x0, sizeof(localaddr)); -// memset (&remoteaddr, 0x0, sizeof(remoteaddr)); - writecnt = 0; - readcnt = 0; - islisten = 0; -}; - -TCP::TCP(string h, string p) { - TCP(); - Connect (h,p); -}; - - -int TCP::Listen(int port) { - char buffer[NET_BUFFERSIZE]; - int err, i; - struct addrinfo hints, *res, *rp; - - if (sock > 0) Close(); -// FIXME: solution to get both (IPV4 and IPV6) to work at the same time? - bzero (&hints, sizeof (struct addrinfo)); - hints.ai_flags = AI_PASSIVE; -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - hints.ai_family = AF_INET; -#else - hints.ai_family = AF_INET6; -#endif - hints.ai_socktype = SOCK_STREAM; - if ((err = getaddrinfo (NULL, itoa(buffer, port, 32), &hints, &res)) != 0) { - return 0; - } - - // - // walk through all results until we could connect - // - for (rp = res; rp != NULL; rp = rp->ai_next) { - sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sock == -1) continue; - - i = 1; - if ((err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof (i))) != 0) { - printf ("%s:%d setsockopt error\n", __FILE__, __LINE__); - } - - if ((err = bind (sock, rp->ai_addr, rp->ai_addrlen)) < 0) { - close (sock); - sock = -1; - continue; - } - if (listen (sock, 8) < 0) { // maximum of 8 connections at the time - close (sock); - sock = -1; - continue; - } - break; - } - - freeaddrinfo (res); - - if (rp == NULL) { - sock = -1; - return 0; - } - - islisten = 1; - - return 1; -}; - - -TCP* TCP::Accept() { - fd_set rfds; - struct timeval tv; - int retval; - SOCKET newsock; - struct sockaddr_storage cliaddr; - socklen_t cliaddr_len = sizeof(struct sockaddr_storage); - TCP *tcp = NULL; - - if (sock <= 0) return NULL; - - FD_ZERO(&rfds); - FD_SET(sock, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 1000; - - retval = select (sock+1, &rfds, NULL, NULL, &tv); - if (retval == -1 && errno == EINTR) { - retval = 0; - } - else if (retval == -1) { - return NULL; - } - else if (retval) { -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - newsock = accept (sock, (struct sockaddr *) &cliaddr, (int*) &cliaddr_len); -#else - newsock = accept (sock, (struct sockaddr *) &cliaddr, &cliaddr_len); -#endif - if (newsock < 0) return NULL; - tcp = new TCP(); - tcp->SetSocket(newsock, &cliaddr, cliaddr_len); - - return tcp; - } - return NULL; -} - - -int TCP::Connect(string h, string p) { - remote_host = h; - remote_port = p; - - return Connect(); -}; - - -int TCP::Connect(string hostport, int defaultport) { - char buffer[32]; - int pos = hostport.rfind(':', hostport.length()); - if (pos == -1) { - remote_port = itoa (buffer, defaultport, 32); - remote_host = hostport; - } - else { - remote_port = hostport.substr (pos+1, hostport.length() - pos); - remote_host = hostport.substr (0, pos); - } - - return Connect(); -}; - - -int TCP::Connect() { - int err, s = 0; - struct addrinfo hints, *res, *rp; - struct timeval timeout; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6 - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; - - err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res); - if (err != 0) { - fprintf(stderr, "getaddrinfo: Host:'%s' Port:'%s' Error:%s\n", remote_host.c_str(), remote_port.c_str(), gai_strerror(err)); - return 0; - } - - // - // walk through all results until we could connect - // - for (rp = res; rp != NULL; rp = rp->ai_next) { - s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - - // setup timeout to max 2 secs - timeout.tv_sec = 2; - timeout.tv_usec = 0; - setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)); - - if (s == -1) continue; - if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) { - sock = s; - break; - } - close(s); - } - - freeaddrinfo(res); - - // - // connect not successfull - // - if (rp == NULL) return 0; - - writecnt = 0; - readcnt = 0; - - return 1; -}; - - -long int TCP::ReadPop (char *buffer, long int pktlen, long int bufferlen) { - memmove (buffer, buffer+pktlen, bufferlen-pktlen); - return bufferlen-pktlen; -} - - -long int TCP::Read(char *buffer, long int len) { - long int len_ = len; - - if (sock <= 0) return -2; - len_ = recv (sock, buffer, len, 0); - - if (len_ < 0 && errno == EAGAIN) len_ = 0; - else if (len_ < 0 && errno != EAGAIN) { -#ifdef BUILD_WINDOWS - printf ("%s ERROR:%s\n", __FUNCTION__, strerror (errno)); -#else - fprintf (stderr, "%s ERROR:%s\n", __FUNCTION__, strerror (errno)); -#endif - len_ = -2; - } - else if (len_ == 0) len_ = -1; - if (len_ < 0) Close(); - - readcnt += len_; - - return len_; -}; - - -long int TCP::ReadTimeout(char *buffer, long int len, int timeout) { - int data = IsData (timeout); - - if (data > 0) return Read (buffer, len); - else if (data < 0) return -1; - else return 0; -}; - - -////////////////////////////////////////////////////////// -// -// write data, generate no signal if some error occures -long int TCP::Write(char *buffer, long int len) { - int i; - int to = NET_MAX_RETRY; - - if (sock <= 0) return -1; - - do { - i = send (sock, buffer, len, MSG_NOSIGNAL); - } while (i == -1 && (to--) > 0 && errno == EINTR); - - if (i < 0) Close (); - writecnt += i; - - return i; -}; - - -void TCP::Close() { -#ifdef BUILD_WINDOWS - closesocket(sock); -#else - if (sock > 0) close (sock); -#endif - sock = -1; - islisten = false; -}; - - -void TCP::SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen) { - char host[NET_HOSTLEN]; - char port[NET_PORTLEN]; - int err; - - if (sock > 0) Close(); - if (s > 0) { - sock = s; - - if (saddr != NULL) { - memcpy (&peeraddr, saddr, sizeof(peeraddr)); - if ((err = getnameinfo ((struct sockaddr*) saddr, saddrlen, host, NET_HOSTLEN, - port, NET_PORTLEN, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) { - remote_host = host; - remote_port = port; - } else { - printf ("error: getnameinfo"); -/* if (err == EAI_AGAIN) printf ("EAI_AGAIN\n"); - if (err == EAI_BADFLAGS) printf ("EAI_BADFLAGS\n"); - if (err == EAI_FAIL) printf ("EAI_FAIL\n"); - if (err == EAI_FAMILY) printf ("EAI_FAMILY\n"); - if (err == EAI_MEMORY) printf ("EAI_MEMORY\n"); - if (err == EAI_NONAME) printf ("EAI_NONAME\n"); - if (err == EAI_OVERFLOW) printf ("EAI_OVERFLOW\n"); - if (err == EAI_SYSTEM) printf ("EAI_SYSTEM\n"); */ // windows seem to have different error codes - } - } - } - else sock = -1; -}; - - -int TCP::IsConnected() { - return (sock > 0); -}; - - -int TCP::IsData(int timeout) { - fd_set sockset; - struct timeval tval; - - if (sock <= 0) return -1; - - FD_ZERO (&sockset); - FD_SET (sock, &sockset); - tval.tv_sec = timeout / 1000; - tval.tv_usec = (timeout % 1000); - if ((select (sock + 1, &sockset, NULL, NULL, &tval)) != -1) { - if (FD_ISSET (sock, &sockset)) return 1; - return 0; - } - else { - if (errno == EBADF) sock = -1; - } - return 0; -}; - - -/* - * 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]; - 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()) { - Connect (host, port); - } - - if (!IsConnected()) return -1; - - // - // send http request - // - 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)); - - // - // 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; - } - } - - // - // 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; - - 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; - } - } - - return buffpos; -}; - - -// 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; - - for (i = 0; i < 5; i++) url[i] = toupper(url[i]); - - // - // 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; - } - - 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; - } - } - - if (host != NULL) *host = h; - if (file != NULL) *file = f; - if (port != NULL) *port = p; - - return retval; -}; - - -const string TCP::GetRemoteAddr() { - string ret = ""; - socklen_t addrlen = sizeof (peeraddr); - char host[256] = ""; - char port[256] = ""; - - if (getnameinfo ((struct sockaddr*)&peeraddr, addrlen, host, 255, port, 255, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - printf ("getnameinfo error: %s\n", strerror(errno)); - } - - ret = (string)host + ":" + (string)port; - - return ret; -}; - - -const string TCP::GetLocalAddr() { - string ret; - - return ret; -}; - - diff --git a/tcp.h b/tcp.h deleted file mode 100644 index d1a1917..0000000 --- a/tcp.h +++ /dev/null @@ -1,123 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// tcp.h is part of TestModbus-Server. -// -///////////////////////////////////////////////////////////////////////////////// - -#ifndef _TCP_H_ -#define _TCP_H_ - -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - -#define WIN32_LEAN_AND_MEAN - -#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000 -#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) - -#ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x501 -#endif -#ifndef NTDDI_VERSION -# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT) -#endif - -// #include -#include -#include -#include -#include - -#define socklen_t size_t - -#ifndef bzero -#define bzero(__z__, __x__) memset (__z__, 0x0, __x__) -#endif - -#ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL 0 -#endif - -#else - -#include -#include -#include -#include -#include -#include - -#endif - -#include - -using namespace std; - -#define SOCKET int - -#define NET_HOSTLEN 256 -#define NET_PORTLEN 6 -#define NET_BUFFERSIZE 4096 -#define NET_MAX_RETRY 5 // retry to send data EINTR -#define NET_MAX_TIMEOUT 30000 // timeout in ms - - -/************************************************************************ - * - * global functions needed for networking - * - */ -int dns_filladdr (string host, string port, int ai_family, - struct sockaddr_storage *sAddr); -char *itoa(char* buffer, int number, int size); -void UDPTCPNetwork_Startup(); -extern int UDPTCPNetwork_init; - - -/************************************************************************ - * tcp related functions - */ -class TCP { -private: - SOCKET sock; - struct sockaddr_storage peeraddr; - string remote_host; - string remote_port; - int readcnt; - int writecnt; - int islisten; - - int WebHeaderGetParamValue(std::string line, std::string *parm, std::string *value); -public: - TCP(); - TCP(SOCKET s); - TCP(string h, string p); - TCP(string hostport, int defaultport); - ~TCP(); - - int Connect(); - int Connect(string h, string p); - int Connect(string hostport, int defaultport); - long int ReadPop (char *buffer, long int pktlen, long int bufferlen); - long int ReadTimeout(char *buffer, long int len, int timeout); - long int Read(char *buffer, long int len); - long int Write(char *buffer, long int len); - void Close(); - int IsConnected(); - int IsData(int timeout); // timeout in ms; - int IsListen() { return islisten; }; - - int Listen(int port); - TCP* Accept(); - - SOCKET GetSocket() { return sock; }; - void SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen); - - const string GetRemoteAddr(); - const string GetLocalAddr(); - - int WebGetURLElements (string url, string *host, string *port, string *file); - int WebGetFile (string url, char *buffer, int maxsize, char *formdata); -}; - -#endif -