add .gitignore
[tedtools.git] / tcp.c
diff --git a/tcp.c b/tcp.c
index 26afeaf..a9295e4 100644 (file)
--- a/tcp.c
+++ b/tcp.c
@@ -105,7 +105,7 @@ TC_ClientInitConnection(TC_Connection *cs, char *name, u_int32_t port) {
                        ntohs(cs->serv_addr.sin_port),strerror(errno));
 
         if (setsockopt(cs->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
-                tlog(TL_CRIT|TL_EXIT, "socketsockopt failed: %s (d%)", strerror(errno), errno);
+                tlog(TL_CRIT|TL_EXIT, "socketsockopt failed: %s (%d)", strerror(errno), errno);
                 return CS_ERROR;
         }
 
@@ -156,9 +156,27 @@ TC_AcceptTcp(TC_Connection *cs) {
 TC_Connection *
 TC_fillConnection(TC_Connection *sc, char *name, u_int32_t port) {
        if ( !sc ) 
-               sc = (TC_Connection *)t0malloc(sizeof(TC_Connection));
+               sc = (TC_Connection *)tmalloc(sizeof(TC_Connection));
+       memset(sc, 0, sizeof(TC_Connection));
        sc->serv_addr.sin_family = AF_INET;
-       sc->serv_addr.sin_addr.s_addr = (name) ? inet_addr(name) : htonl(INADDR_ANY);
+       sc->serv_addr.sin_addr.s_addr = (name && *name != '*' ) ? inet_addr(name) : htonl(INADDR_ANY);
+       if ( sc->serv_addr.sin_addr.s_addr == INADDR_NONE ) {
+               struct hostent *host;
+
+               /*
+                * Can't parse address: it's a DNS Name
+                */
+               host = gethostbyname(name);
+               if ( host && host->h_addrtype == AF_INET ) {
+                       memcpy(&sc->serv_addr.sin_addr.s_addr, host->h_addr_list[0], 
+                               sizeof(&sc->serv_addr.sin_addr.s_addr));
+               } else {
+                       tlog(TL_CRIT,"gethostbyname: %s - %s", name, hstrerror(h_errno));
+                       sc->state = CS_ERROR;
+                       return sc;
+               }
+       }
+       
        sc->serv_addr.sin_port = htons(port);
        sc->state = CS_NOTINITED;
        return sc; 
@@ -184,6 +202,10 @@ TC_ServerInitConnect( TC_Connection        *cs ) {
        if (fcntl(cs->fd,F_SETFL,flags|O_NDELAY) < 0 )
                tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno));
 
+       flags=1;
+       if (setsockopt(cs->fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)) < 0)
+               tlog(TL_ALARM, "socketsockopt failed: %s (%d)", strerror(errno), errno);
+
        if ( connect(cs->fd, (struct sockaddr *) &(cs->serv_addr),
                sizeof(struct sockaddr_in)) < 0 ) {
                if ( errno == EINPROGRESS || errno == EALREADY ) {
@@ -191,7 +213,7 @@ TC_ServerInitConnect( TC_Connection *cs ) {
                        return CS_INPROCESS; 
                } else if (errno != EISCONN && errno != EALREADY &&
                        errno != EWOULDBLOCK && errno != EAGAIN) {
-                       tlog(TL_DEBUG,"open4: %s:%d - %s",
+                       tlog(TL_DEBUG,"connect: %s:%d - %s",
                                inet_ntoa(cs->serv_addr.sin_addr), ntohs(cs->serv_addr.sin_port),
                                strerror(errno));
                        shutdown(cs->fd,SHUT_RDWR);
@@ -208,12 +230,12 @@ TC_ServerInitConnect( TC_Connection       *cs ) {
        }
 
        cs->state = CS_INPROCESS;
-       return TC_ServerConnect( cs );
+       return TC_ServerConnect( cs, 0 );
 }
        
 
 u_int32_t
-TC_ServerConnect( TC_Connection *cs ) {
+TC_ServerConnect( TC_Connection *cs, int timeout ) {
        struct pollfd   pfd;
        int ret;
 
@@ -223,7 +245,7 @@ TC_ServerConnect( TC_Connection *cs ) {
        pfd.fd = cs->fd;
        pfd.events = POLLOUT;
        pfd.revents = 0;
-       ret = poll( &pfd, 1, 0 );
+       ret = poll( &pfd, 1, timeout );
        if ( ret<0 ) {
                tlog( TL_CRIT, "TC_ServerConnect: poll: %s",
                        strerror(errno));
@@ -252,6 +274,8 @@ TC_ReadyIO( TC_Connection **cs, int number, int timeout ) {
        int ret,i, fdnum=0;
 
        if ( number==0 || cs ==NULL ) {
+               if (timeout<0)
+                       timeout=1000;
                usleep( timeout * 1000.0 );
                return 0;
        }
@@ -266,6 +290,14 @@ TC_ReadyIO( TC_Connection **cs, int number, int timeout ) {
                }
                cs[i]->readyio=0;
        }
+
+       if ( fdnum==0 ) {
+               tfree(pfd);
+               if (timeout<0)
+                       timeout=1000;
+               usleep( timeout * 1000.0 );
+               return 0;
+       }       
        ret = poll( pfd, fdnum, timeout );
        if ( ret<0 ) {
                tlog( TL_CRIT, "TC_ReadyIO: poll: %s",
@@ -307,17 +339,22 @@ TC_Send( TC_Connection *cs ) {
        if ( cs->state == CS_ERROR )
                return CS_ERROR;
 
-       if ( cs->state != CS_SEND ) {
+       if ( cs->state != CS_SEND || cs->ptr == NULL ) {
                cs->state = CS_SEND;
-               cs->ptr = cs->buf;
+               cs->ptr = (char*)cs->buf;
+               cs->len = cs->buf->len;
+
+               /* convert fields to network byteorder */
+               cs->buf->len = htonl(cs->buf->len);
+               cs->buf->type = htonl(cs->buf->type);
        }
 
-       if ( cs->ptr - cs->buf >= cs->len ) {
+       if ( cs->ptr - (char*)cs->buf >= cs->len ) {
                cs->state = CS_FINISHSEND;
                return CS_FINISHSEND;
        }
 
-       if ((sz=write(cs->fd, cs->ptr, cs->len - (cs->ptr - cs->buf)))==0 ||
+       if ((sz=write(cs->fd, cs->ptr, cs->len - (cs->ptr - (char*)cs->buf)))==0 ||
                (sz < 0 && (errno == EWOULDBLOCK || errno == EAGAIN))) {
 
                /* SunOS 4.1.x, are broken and select() says that
@@ -339,8 +376,11 @@ TC_Send( TC_Connection *cs ) {
 
        cs->ptr += sz;
 
-       if ( cs->ptr - cs->buf >= cs->len ) {
+       if ( cs->ptr - (char*)cs->buf >= cs->len ) {
                cs->state = CS_FINISHSEND;
+               /* revert byteorder conversion */
+               cs->buf->len = ntohl(cs->buf->len);
+               cs->buf->type = ntohl(cs->buf->type);
                return CS_FINISHSEND;
        }
        
@@ -349,32 +389,40 @@ TC_Send( TC_Connection *cs ) {
 
 static void 
 resizeCS( TC_Connection *cs, int sz ) {
-       int diff = cs->ptr - cs->buf;
+       int diff = cs->ptr - (char*)cs->buf;
+
        if ( cs->len >= sz )
                return; 
        cs->len = sz;
-       cs->buf = (char*)trealloc( (void*)cs->buf, cs->len );
-       cs->ptr = cs->buf + diff;
+       cs->buf = (TCMsg*)trealloc( (void*)cs->buf, cs->len );
+       cs->ptr = ((char*)cs->buf) + diff;
 }
 
 u_int32_t
-TC_Read( TC_Connection *cs ) {
+TC_Read( TC_Connection *cs, size_t maxsize ) {
        int sz, totalread = -1, toread=0, alreadyread;
 
        if ( cs->state == CS_ERROR )
                return CS_ERROR;
 
-       if (cs->state != CS_READ ) {
+       if (cs->state != CS_READ || cs->ptr == NULL ) {
                cs->state = CS_READ;
-               cs->ptr = cs->buf;
+               cs->ptr = (char*)cs->buf;
+               cs->len = 0;
        }
 
-       alreadyread = cs->ptr - cs->buf;
-       if ( alreadyread < sizeof(u_int32_t) ) {
-               toread = sizeof(u_int32_t) - alreadyread;
-               resizeCS(cs, sizeof(u_int32_t));
+       alreadyread = cs->ptr - (char*)cs->buf;
+       if ( alreadyread < TCMSGHDRSZ ) {
+               toread = TCMSGHDRSZ - alreadyread;
+               resizeCS(cs, TCMSGHDRSZ);
        } else {
-               totalread = *(u_int32_t*)(cs->buf);
+               totalread = ntohl(cs->buf->len);
+               if ( maxsize > 0 && totalread > maxsize )
+               {
+                       tlog(TL_ALARM,"TC_Read: message size (%d b) is greater than max allowed (%d b)", totalread, maxsize);
+                       cs->state = CS_ERROR;
+                       return CS_ERROR;
+               }
                toread = totalread - alreadyread;
                if ( toread == 0 ) {
                        cs->state = CS_FINISHREAD;
@@ -393,7 +441,13 @@ TC_Read( TC_Connection *cs ) {
                return CS_ERROR;
        }
        
-
+       if ( alreadyread < TCMSGHDRSZ  && alreadyread + sz >= TCMSGHDRSZ ) {
+               /* 
+                * we just read header - we can get totalread value. 
+                */
+               totalread = ntohl(cs->buf->len);
+       }
+       
        cs->ptr += sz;
        alreadyread += sz;
        if ( sz == 0 && alreadyread != totalread ) {
@@ -401,7 +455,13 @@ TC_Read( TC_Connection *cs ) {
                cs->state = CS_ERROR;
                return CS_ERROR;
        }
-       cs->state = ( alreadyread == totalread ) ? CS_FINISHREAD : CS_READ;
+
+       if ( alreadyread == totalread ) {
+               cs->buf->len = ntohl(cs->buf->len);
+               cs->buf->type = ntohl(cs->buf->type);
+               cs->state = CS_FINISHREAD;
+       }
+
        return cs->state;
 }
 
@@ -422,26 +482,28 @@ TC_FreeConnection( TC_Connection *cs ) {
 }
 
 u_int32_t 
-TC_Talk( TC_Connection *cs ) {
-       u_int32_t ret = TC_ServerInitConnect( cs );
+TC_Talk( TC_Connection *cs, size_t maxsize  ) {
+       if ( cs->state==CS_NOTINITED ) 
+               TC_ServerInitConnect( cs );
 
-       while( ret == CS_INPROCESS ) {
-               ret =  TC_ServerConnect(cs);
-       }
+       while( cs->state == CS_INPROCESS ) 
+               TC_ServerConnect(cs, 100);
 
-       if ( ret != CS_CONNECTED )
-               return ret;
+       if ( cs->state != CS_CONNECTED )
+               return cs->state;
        
-       while( ret != CS_FINISHSEND ) {
-               ret = TC_Send(cs);
-               if ( ret == CS_ERROR ) return ret;
+       cs->state = CS_SEND;
+       cs->ptr = NULL;
+       while( cs->state != CS_FINISHSEND ) {
+               while( !TC_ReadyIO( &cs, 1, 100) );
+               if ( TC_Send(cs) == CS_ERROR ) return CS_ERROR;
        }
 
        cs->state = CS_READ;
-       cs->ptr = cs->buf;
+       cs->ptr = NULL;
        while( cs->state != CS_FINISHREAD ) {
                while( !TC_ReadyIO( &cs, 1, 100) );
-               if ( TC_Read(cs) == CS_ERROR ) return CS_ERROR;
+               if ( TC_Read(cs, maxsize) == CS_ERROR ) return CS_ERROR;
        }
 
        return CS_OK;