commit 05d86a44568d7270ee229801923614f245264b93 Author: steffen Date: Sun Aug 13 21:52:04 2017 +0000 Initial revision diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e40a81c --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +# .SILENT: + +VERSION=0.1 +PREFIX=/usr/local +ETCPREFIX=/etc + +CXX=g++ +CXXFLAGS= -ggdb -fPIC -pg -Wno-write-strings -I./ +LDFLAGS= -lm -lc -pg + +DEFAULT_TCPPORT=6131 +DEFAULT_UDPPORT=6131 +DEFAULT_SERVER=localhost + +OBJLIB=network.o udp.o tcp.o +INCLIB=config.h UDPTCPNetwork.h +OBJLIB_NAME=UDPTCPNetwork +TARGET=lib$(OBJLIB_NAME).so.$(VERSION) + +DISTNAME=libUDPTCPNetwork-$(VERSION) +DEPENDFILE=.depend + +all: dep $(TARGET) test-udp test-tcp + +test-tcp: $(TARGET) test-tcp.o config.h + $(CXX) test-tcp.o -o $@ $(LDFLAGS) -lUDPTCPNetwork -L./ -I./ + +test-udp: $(TARGET) test-udp.o config.h + $(CXX) test-udp.o -o $@ $(LDFLAGS) -lUDPTCPNetwork -L./ -I./ + +install: $(TARGET) + cp -f $(TARGET) $(PREFIX)/lib/ + ln -sf $(TARGET) $(PREFIX)/lib/lib$(OBJLIB_NAME).so + cp -f UDPTCPNetwork.h $(PREFIX)/include/ + +uninstall: + rm -f $(PREFIX)/lib/$(TARGET) + rm -f $(PREFIX)/lib/lib$(OBJLIB_NAME).so + rm -f $(PREFIX)/include/UDPTCPNetwork.h + +rebuild: clean all + +$(TARGET): $(OBJLIB) $(INCLIB) + $(CXX) -shared -Wl,-soname,lib$(OBJLIB_NAME).so -o $(TARGET) $^ -lc $(LDFLAGS) + ln -sf $(TARGET) lib$(OBJLIB_NAME).so + ar rcs lib$(OBJLIB_NAME).a $(OBJLIB) + +dep: + $(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE) + +clean: + rm test-tcp -rf + rm test-udp -rf + rm -rf gmon.out + rm *.s -rf + rm *.o -rf + rm *.oo -rf + rm *~ -rf + rm -rf config.h + rm -rf .depend + rm -rf *.so + rm -rf *.a + rm -rf *.so.* + + +cleanall: clean + +source: cleanall + +config: + echo "#ifndef _CONFIG_H_" > config.h + echo "#define _CONFIG_H_" >> config.h + echo "" >> config.h + echo "#define UDPTCPNETWORK_VERSION \"$(VERSION)\"" >> config.h + echo "" >> config.h + echo "#define PREFIX \"$(PREFIX)\"" >> config.h + echo "#define ETCPREFIX \"$(ETCPREFIX)\"" >> config.h + echo "" >> config.h + echo "#endif" >> config.h + +dist: clean + mkdir -p $(DISTNAME) + cp -rf Makefile $(DISTNAME) + cp -rf *.h $(DISTNAME) + cp -rf *.cc $(DISTNAME) + tar cvzf $(DISTNAME).tgz --exclude=*/CVS/* --exclude=*/CVS/ $(DISTNAME) + rm -rf $(DISTNAME) + +-include $(DEPENDFILE) + diff --git a/UDPTCPNetwork.h b/UDPTCPNetwork.h new file mode 100644 index 0000000..98b7b34 --- /dev/null +++ b/UDPTCPNetwork.h @@ -0,0 +1,105 @@ + +#ifndef _UDPTCPNETWORK_H_ +#define _UDPTCPNETWORK_H_ + +#include +#include +#include + +#include + +using namespace std; + +#define NET_HOSTLEN 256 +#define NET_PORTLEN 6 +#define NET_BUFFERSIZE 1024 +#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); + + + +/************************************************************************ + * + * udp related functions + * + */ +class UDP { +private: + int sock; + int localport; + size_t readcnt; + size_t writecnt; + +public: + UDP(); + ~UDP(); + + int Listen(int port); + + long int ReadTimeout(string *srcaddr, char *buffer, long int len, int timeout_ms); + long int Read(string *srcaddr, char *buffer, long int len); + long int Write(string destaddr, char *buffer, long int len); + + void Close(); + int IsListen(); + int IsData(int timeout_ms); // timeout in ms; + + int GetSocket() { return sock; }; +}; + + +/************************************************************************ + * tcp related functions + */ +class TCP { +private: + int sock; +// struct sockaddr_storage localaddr; +// struct sockaddr_storage remoteaddr; + string remote_host; + string remote_port; + int readcnt; + int writecnt; + +public: + TCP(); + TCP(int s); + TCP(string h, string p); + TCP(string hostport, int defaultport); + ~TCP(); + + int Connect(); + int Connect(string h, string p); + int Connect(string host, 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 Listen(int port); + TCP* Accept(); + + int GetSocket() { return sock; }; + void SetSocket(int s, struct sockaddr_storage *saddr, int saddrlen); + + const string WebGetURLHost (string url); + const string WebGetURLPort (string url); + const string WebGetURLFile (string url); + int WebGetFile (string url, char *buffer, int maxsize); +}; + +#endif + diff --git a/network.cc b/network.cc new file mode 100644 index 0000000..7683211 --- /dev/null +++ b/network.cc @@ -0,0 +1,48 @@ + +#include "UDPTCPNetwork.h" + +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include /* memset() */ + +using namespace std; + +char dnsip[NET_HOSTLEN]; + + +// +// 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; +} diff --git a/tcp.cc b/tcp.cc new file mode 100644 index 0000000..ca1bd34 --- /dev/null +++ b/tcp.cc @@ -0,0 +1,401 @@ +/* + * + */ + +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include +#include /* memset() */ +#include + +#include "UDPTCPNetwork.h" + +TCP::~TCP() { + Close(); +} + +TCP::TCP() { + sock = 0; + writecnt = 0; + readcnt = 0; +}; + +TCP::TCP(int s) { + TCP(); + sock = s; +// memset (&localaddr, 0x0, sizeof(localaddr)); +// memset (&remoteaddr, 0x0, sizeof(remoteaddr)); + writecnt = 0; + readcnt = 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(); + + bzero (&hints, sizeof (struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET6; + 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; + + if ((err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &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) { + close (sock); + sock = -1; + continue; + } + break; + } + + freeaddrinfo (res); + + if (rp == NULL) { + sock = -1; + return 0; + } + return 1; +}; + + +TCP* TCP::Accept() { + fd_set rfds; + struct timeval tv; + int retval, newsock, err, i; + struct sockaddr_storage cli_addr; + unsigned int cli_len; + char host[NET_BUFFERSIZE]; + char port[NET_BUFFERSIZE]; + TCP *tcp = NULL; + + if (sock <= 0) return NULL; + + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + + retval = select (sock+1, &rfds, NULL, NULL, &tv); + if (retval == -1 && errno == EINTR) { + retval = 0; + } + else if (retval == -1) { + return NULL; + } + + else if (retval) { + newsock = accept (sock, (struct sockaddr *) &cli_addr, &cli_len); + if (newsock < 0) return NULL; + + tcp = new TCP(); + tcp->SetSocket(newsock, &cli_addr, cli_len); + return tcp; + } + return NULL; +} + + +int TCP::Connect(string h, string p) { + int i = 0; + +// memset (&localaddr, 0x0, sizeof(localaddr)); +// memset (&remoteaddr, 0x0, sizeof(remoteaddr)); +// i = dns_filladdr(h, p, AF_INET, &remoteaddr); +// if (i == 0) return 0; + 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; + struct addrinfo hints, *res, *rp; + + 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; + + s = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + 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; + if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break; + close(sock); + } + + 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_ = read (sock, (void*)buffer, len); + // printf ("read: "); debug_mem(buffer, len_); + + if (len_ < 0 && errno == EAGAIN) len_ = 0; + else if (len_ < 0 && errno != EAGAIN) { + // fprintf (stderr, "%s ERROR:%s\n", __FUNCTION__, strerror (errno)); + 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; +}; + + +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, 0); + } while (i == -1 && (to--) > 0 && errno == EINTR); + + if (i < 0) Close (); + writecnt += i; + + return i; +}; + + +void TCP::Close() { + if (sock > 0) close (sock); + sock = -1; +}; + + +void TCP::SetSocket(int s, struct sockaddr_storage *saddr, int saddrlen) { + char host[NET_HOSTLEN]; + char port[NET_PORTLEN]; + int err; + + + if (sock > 0) Close(); + if (s > 0) { + sock = s; + + if (saddr != NULL) { + 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 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; +}; + + +int TCP::WebGetFile (string url, char *buffer, int maxsize) { + char outdata[NET_BUFFERSIZE]; + char indata[NET_BUFFERSIZE]; + char host[NET_HOSTLEN]; + char port[NET_PORTLEN]; + int breakup, len, head, i, buffpos = 0; + + 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); + 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); + } + + else if (strncmp (indata+i, "Content-Length:", 15) == 0) { + i = i + 16; + } + + else if (strncmp (indata+i, "403 ", 4) == 0) breakup = 1; + else i++; + } + } + + // read data + while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) { + i = len; + if (i > maxsize-buffpos) i = maxsize-buffpos; + if (i > 0) { + memcpy (buffer+buffpos, indata, i); + buffpos += i; + } + } + + 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; +}; + +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"; + + return result; +}; + +const string TCP::WebGetURLFile (string url) { + string result; + int posEServPort = 0; // end Server:Port + + posEServPort = url.find("/", 7); + result = url.substr (posEServPort); + + return result; +}; + diff --git a/test-tcp.cc b/test-tcp.cc new file mode 100644 index 0000000..cf30f82 --- /dev/null +++ b/test-tcp.cc @@ -0,0 +1,123 @@ + +#include +#include + +#include "UDPTCPNetwork.h" + +#define DEFAULT_PORT 12345 + + +void server () { + TCP tcpserver; + TCP *connection; + int i, timeout; + pid_t pid; + char buffer[NET_BUFFERSIZE]; + + // + // start the server + if (tcpserver.Listen(DEFAULT_PORT) != 1) { + printf ("cloud not start the tcp server\n"); + exit (1); + } + + // + // check for connections + for (timeout = 5; timeout > 0; timeout--) { + connection = tcpserver.Accept(); + if (connection != NULL) { + // + // someone connected - create new process + // take care of parallel processing (parent is always the server) + // + printf (" server: got a connection forking new process\n"); + pid = fork(); + if (pid == 0) { + // + // child process - always close server since it will handeled + // by the parent process. Make sure the client exits and never + // returns. + tcpserver.Close(); + i = connection->ReadTimeout(buffer, NET_BUFFERSIZE, 1000); + if (i > 0) { + int c; + + printf (" server: (child) got: '%s'\n", buffer); + for (c = 0; c < i; c++) buffer[c] = toupper(buffer[c]); + connection->Write(buffer, i); + } + // + // just delete the class object, it will close the client connection + delete (connection); + + // + // exit child process + exit (1); + } + else { + // + // parent process - just close the client connection + // it will be handeled by the child process. + delete (connection); + } + } + sleep (1); + } +}; + + +void client () { + TCP tcpclient; + char buffer[NET_BUFFERSIZE]; + int i; + + sleep (1); // wait one second to start the server + + // + // connect to the server + if (tcpclient.Connect ("localhost", DEFAULT_PORT) != 1) { + printf ("cloud not connect to server\n"); + exit (1); + } + + // + // send some data + snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test."); + printf ("client:send '%s' to the server.\n", buffer); + if (tcpclient.Write(buffer, strlen (buffer)) != strlen (buffer)) { + printf ("could not send all data.\n"); + exit (1); + } + + // + // read some data (wait maximum 10x1000ms) + for (i = 10; i > 0; i--) + if (tcpclient.ReadTimeout(buffer, NET_BUFFERSIZE, 1000) > 0) { + printf ("client:got '%s' from server.\n", buffer); + break; + } + + // + // close connection + tcpclient.Close(); +}; + + + +int main (int argc, char **argv) { + pid_t pid; + + pid = fork(); + if (pid == 0) { // child process + client(); + client(); + client(); + client(); + } + else { // parent process + server(); + } + + return 0; +}; + diff --git a/test-udp.cc b/test-udp.cc new file mode 100644 index 0000000..dd05bad --- /dev/null +++ b/test-udp.cc @@ -0,0 +1,92 @@ + +#include +#include + +#include "UDPTCPNetwork.h" + + +/**************************************************************************** + * + * server: only converts one message to upper cases and quits + * + */ +class Server { + private: + UDP udp; + public: + Server() { udp.Listen(12345); }; + ~Server() {}; + void Loop(); +}; + + +void Server::Loop() { + char buffer[NET_BUFFERSIZE]; + int i; + string srcaddr; + + udp.ReadTimeout (&srcaddr, buffer, NET_BUFFERSIZE, 2000); + printf (" server got : %s from: '%s'\n", buffer, srcaddr.c_str()); + for (i = 0; i < NET_BUFFERSIZE && buffer[i] != 0; i++) + buffer[i] = toupper (buffer[i]); + printf (" server send: %s to: '%s'\n", buffer, srcaddr.c_str()); + udp.Write(srcaddr, buffer, i+1); +}; + + +/**************************************************************************** + * + * client: sends just one little text to the udp server + * + */ +class Client { + private: + UDP udp; + public: + Client() { udp.Listen(12346); }; + ~Client() {}; + void Loop(); +}; + +void Client::Loop() { + char buffer[NET_BUFFERSIZE]; + string srcaddr = "localhost:12345"; + + sprintf (buffer, "only some test."); + + printf ("client send: %s to: '%s'\n", buffer, srcaddr.c_str()); + udp.Write(srcaddr, buffer, strlen (buffer)); + udp.ReadTimeout(&srcaddr, buffer, NET_BUFFERSIZE, 2000); + printf ("client got : %s from: '%s'\n", buffer, srcaddr.c_str()); +}; + + +/**************************************************************************** + * + * udp test application: + * + * creating a server and a client object. Where the client send some text + * to the server who converts it to upper case and sends it back to the + * client. + * + * Due to forking, both processes are running separated from each other and + * are NOT checked with waitforpid. So make sure you kill them yourself. + * + */ +int main (int argc, char **argv) { + Server server; + Client client; + + pid_t pid; + + pid = fork(); + if (pid == 0) { // child process + client.Loop (); + } + else { // parent process + server.Loop (); + } + + return 0; +}; + diff --git a/test.cc b/test.cc new file mode 100644 index 0000000..2d104be --- /dev/null +++ b/test.cc @@ -0,0 +1,17 @@ + +#include +#include +#include "UDPTCPNetwork.h" + +int main (int argc, char **argv) { + UDP udp; + char buffer[256] = "Hallo"; + + udp.Listen(12345); + snprintf (buffer, 256, "ein test, Parameter 0:%s", argv[0]); + + udp.Write("www.gulpe.de:12345", buffer, strlen (buffer)); + + return 0; +}; + diff --git a/udp.cc b/udp.cc new file mode 100644 index 0000000..9e3e1a6 --- /dev/null +++ b/udp.cc @@ -0,0 +1,156 @@ +/* + * + */ + +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include +#include /* memset() */ +#include + +#include "UDPTCPNetwork.h" + +UDP::UDP() { + sock = -1; + localport = -1; + writecnt = 0; + readcnt = 0; +}; + + +UDP::~UDP() { + Close(); +} + + +void UDP::Close () { + if (sock > -1) close (sock); + sock = -1; +} + + +int UDP::Listen(int port) { + struct sockaddr_in servAddr; + + // + // socket creation + // + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno)); + return 0; + } + + // + // bind local server port + // + localport = port; + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(localport); + if (bind (sock, (struct sockaddr *) &servAddr,sizeof(servAddr)) < 0) { + printf("%s: bind error: %s \n",__FUNCTION__, strerror(errno)); + return 0; + } + return 1; +} + + +long int UDP::ReadTimeout(string *source, char *buffer, long int len, int timeout_ms) { + int i; + + i = IsData(timeout_ms); + if (i > 0) { + return Read (source, buffer, len); + } + else + return i; +} + +long int UDP::Read(string *source, char *buffer, long int len) { + int n; + socklen_t addrlen; + sockaddr_in srcAddr; + + if (!IsListen()) return -1; + + memset(buffer, 0x0, len); + + addrlen = sizeof(srcAddr); + n = recvfrom(sock, buffer, len, 0, (sockaddr *) &srcAddr, &addrlen); + if(n<0) { + printf("%s: recvfrom error:%s\n",__FUNCTION__, strerror(errno)); + return -1; + } + + (*source) = inet_ntoa(srcAddr.sin_addr); + (*source) = (*source) + ":" + to_string (htons(srcAddr.sin_port)); + return n; +} + + +long int UDP::Write(string destaddr, char *buffer, long int len) { + int s; + int addrlen = sizeof (struct sockaddr_in); + struct sockaddr_storage dstAddr; + string host; + string port; + + if (!IsListen()) { + /* socket creation */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno)); + return -1; + } + } + else s = sock; + + int pos = destaddr.rfind(':', destaddr.length()); + if (pos == -1) { + port = "NET_PORT"; + host = destaddr; + } + else { + port = destaddr.substr (pos+1, destaddr.length() - pos); + host = destaddr.substr (0, pos); + } + + dns_filladdr (host, port, PF_INET, &dstAddr); + if (sendto (s, buffer, len, 0, (sockaddr *) &dstAddr, addrlen) == -1) { + printf("%s: sendto error: %s \n",__FUNCTION__, strerror(errno)); + return -1; + } + + if (!IsListen()) close (s); + + return 1; +} + +int UDP::IsListen() { + return (sock != -1); +} + +int UDP::IsData(int timeout_ms) { + fd_set sockset; + struct timeval tval; + + if (sock <= 0) { + printf ("isData:socket error\n"); + return -1; + } + + FD_ZERO (&sockset); + FD_SET (sock, &sockset); + tval.tv_sec = timeout_ms / 1000; + tval.tv_usec = (timeout_ms % 1000); + if (select (sock + 1, &sockset, NULL, NULL, &tval) >= 0) { + if (FD_ISSET (sock, &sockset)) { + return 1; + } + } + return 0; +}