From 5ccdf6dd987be086a8712a4960f770122b1b499b Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 15 Aug 2008 09:37:36 +0000 Subject: Changes for read-loop-server. --- server/src/tcpsocket.cc | 178 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 59 deletions(-) (limited to 'server/src/tcpsocket.cc') diff --git a/server/src/tcpsocket.cc b/server/src/tcpsocket.cc index 4bb7a4b..b6049c7 100644 --- a/server/src/tcpsocket.cc +++ b/server/src/tcpsocket.cc @@ -27,6 +27,9 @@ #include "tcpsocket.h" #include "debug.h" +#include + +//#define WITH_DEBUG // for gethostbyname #include @@ -74,17 +77,28 @@ #include #include -TCPSocket::TCPSocket() +TCPSocket::TCPSocket(std::string name, int sock) throw(TCPSocketException) { - if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - throw TCPSocketException(strerror(errno)); + this->name = name; + if(sock == -1) { + if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + throw TCPSocketException(strerror(errno)); + } } isconnected = false; + this->sock = sock; + +#ifdef WITH_DEBUG + printf("TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); +#endif/*WITH_DEBUG*/ } TCPSocket::~TCPSocket() { +#ifdef WITH_DEBUG + printf("~TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); +#endif/*WITH_DEBUG*/ disconnect(); } @@ -94,13 +108,8 @@ void TCPSocket::listen(unsigned short int port) throw(TCPListenException) { - if(sock == -1) { - throw TCPListenException("Socket not initialized."); - } - - if(isconnected) { - throw TCPListenException("Socket already connected."); - } + if(sock == -1) throw TCPListenException("Socket not initialized."); + if(isconnected) throw TCPListenException("Socket already connected."); struct sockaddr_in socketaddr; memset((char *) &socketaddr, sizeof(socketaddr), 0); @@ -119,35 +128,52 @@ void TCPSocket::listen(unsigned short int port) isconnected = true; } - +/** + ** + ** Accept connections and block until one gets in. + ** Return the new connection on incoming. + ** It throws exceptions if an error occurres. + ** On interrupts, it returns NULL + ** + **/ static int _accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {return accept(sockfd, addr, addrlen);} -TCPSocket TCPSocket::accept() +TCPSocket *TCPSocket::accept() throw(TCPAcceptException) { - TCPSocket child; - - if(sock == -1) { - throw TCPAcceptException("Socket not initialized."); - } - - if(!isconnected) { - throw TCPAcceptException("Socket not connected."); - } + if(sock == -1) throw TCPAcceptException("Socket not initialized."); + if(!isconnected) throw TCPAcceptException("Socket not connected."); // accept new connection and get its connection descriptor struct sockaddr_in ssocketaddr; int csalen = sizeof(ssocketaddr); - child.disconnect(); // We need to close the existing socket - child.sock = _accept(sock, (struct sockaddr*)&ssocketaddr, (socklen_t*)&csalen); - - if (child.sock == -1) { - throw TCPAcceptException(std::string("accept failed - ") + strerror(errno)); + // Select + fd_set fset; + int ret; + FD_ZERO(&fset); + FD_SET(sock, &fset); + if( (ret = select (sock+1, &fset, NULL, NULL, NULL)) < 0) { + if(errno == EINTR) { + printf("Accept got interrupt!\n"); + return NULL; // a signal caused select to return. That is OK with me + } else { + throw TCPAcceptException("Select on socket failed."); + } + } + if(FD_ISSET(sock, &fset)) { + int csock = _accept(sock, (struct sockaddr*)&ssocketaddr, (socklen_t*)&csalen); + TCPSocket *child = new TCPSocket(name + "-child", csock); + + if (child->sock == -1) { + throw TCPAcceptException(std::string("accept failed - ") + strerror(errno)); + } + child->isconnected = true; + return child; + } else { + printf("Accept returned with no socket - This should not happen!\n"); + return NULL; } - - child.isconnected = true; - return child; } @@ -155,11 +181,8 @@ static int _connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addr {return connect(sockfd, serv_addr, addrlen);} void TCPSocket::connect(std::string addr, unsigned short int port) throw(TCPConnectException) - { - if(isconnected) { - throw TCPConnectException("Socket already connected.", "", ""); - } + if(isconnected) throw TCPConnectException("Socket already connected.", "", ""); #ifndef BYPASS_STATICALLOCATIONS // Do DNS lookup @@ -199,7 +222,13 @@ void TCPSocket::connect(std::string addr, unsigned short int port) void TCPSocket::disconnect() { if(sock != -1) { - close(sock); +#ifdef WITH_DEBUG + printf("Closing TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); +#endif/*WITH_DEBUG*/ + int ret = close(sock); + if(ret == -1) { + perror(name.c_str()); + } sock = -1; } isconnected = false; @@ -210,41 +239,69 @@ bool TCPSocket::connected() return sock != -1 && isconnected; } -int TCPSocket::read(char *buf, int size) + + +/** + ** + ** Read read a number of bytes from the network. + ** It returns the number of bytes read. + ** It throws exceptions if an error occurres. + ** On interrupts, it returns -1 + ** + **/ +ssize_t _read(int fd, void *buf, size_t count) { return read(fd, buf, count); } +int TCPSocket::read(char *buf, int size, long timeout) throw(TCPReadException) { int res = 0; - if(sock == -1) { - throw TCPReadException("Socket not initialized."); - } - - if(!isconnected) { - throw TCPReadException("Socket is not connected."); - } - - /* - if( (res = recv(sock, buf, size, MSG_WAITALL)) == -1 ) { - throw TCPReadException(strerror(errno)); - } - */ + if(sock == -1) throw TCPReadException("Socket not initialized."); + if(!isconnected) throw TCPReadException("Socket is not connected."); + + // Select + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout; + + struct timeval *ptv = NULL; + if(timeout >= 0) ptv = &tv; + + fd_set fset; + int ret; + FD_ZERO(&fset); + FD_SET(sock, &fset); + ret = select (sock+1, &fset, NULL, NULL, ptv); + switch(ret) { + case -1: + if(errno == EINTR) { + printf("EINTR - got interrupt\n"); + return -1; // a signal caused select to return. That is OK with me + } else { + throw TCPReadException("Select on socket (read) failed."); + } + break; - // Wait until something is ready to be read ( peek'a'loop ). - errno = EAGAIN; - while( recv(sock, buf, 1, MSG_PEEK) == -1 && errno == EAGAIN) { - usleep(10); - } + case 0: + // timeout + printf("Timeout\n"); + break; - // Now read it - if( (res = recv(sock, buf, size, MSG_DONTWAIT)) == -1 ) { - throw TCPReadException(strerror(errno)); + default: + if(FD_ISSET(sock, &fset)) { + // res = recv(sock, buf, size, MSG_DONTWAIT); + if( (res = _read(sock, buf, size)) == -1 ) { + throw TCPReadException(strerror(errno)); + } + } else { + printf("FD_ISSET failed (timeout?)\n"); + return 0; + } } - // fwrite(buf, size, 1, stdout); fflush(stdout); - return res; } +ssize_t _write(int fd, const void *buf, size_t count) { return write(fd, buf, count); } int TCPSocket::write(char *data, int size) throw(TCPWriteException) { @@ -257,10 +314,13 @@ int TCPSocket::write(char *data, int size) } int res; - if( (res = send(sock, data, size, MSG_WAITALL)) == -1 ) { + // if( (res = send(sock, data, size, MSG_WAITALL)) == -1 ) { + if( (res = _write(sock, data, size)) == -1 ) { throw TCPWriteException(strerror(errno)); } + printf("Outputted %d byes\n", res); + return res; } -- cgit v1.2.3