Added *.dsl files for DEST_DIR.
[yaz-moved-to-github.git] / comstack / tcpip.c
index b467f20..a106805 100644 (file)
@@ -1,10 +1,34 @@
 /*
- * Copyright (c) 1995-2000, Index Data
+ * Copyright (c) 1995-2001, Index Data
  * See the file LICENSE for details.
- * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: tcpip.c,v $
- * Revision 1.35  2000-11-27 15:17:40  adam
+ * Revision 1.43  2001-10-22 16:00:04  adam
+ * Renamed states for COMSTACKs to avoid confusion with events.
+ *
+ * Revision 1.42  2001/10/22 13:57:24  adam
+ * Implemented cs_rcvconnect and cs_look as described in the documentation.
+ *
+ * Revision 1.41  2001/10/12 21:49:26  adam
+ * For accept/recv/send check for EAGAIN if it's differs from EWOULDBLOCK.
+ *
+ * Revision 1.40  2001/08/23 09:02:46  adam
+ * WIN32 fixes: Socket not re-used for bind. yaz_log logs WIN32 error
+ * message.
+ *
+ * Revision 1.39  2001/07/19 19:49:40  adam
+ * Fixed bug in tcpip_set_blocking.
+ *
+ * Revision 1.38  2001/03/21 12:43:36  adam
+ * Implemented cs_create_host. Better error reporting for SSL comstack.
+ *
+ * Revision 1.37  2001/03/08 20:18:55  adam
+ * Added cs_set_blocking. Patch from Matthew Carey.
+ *
+ * Revision 1.36  2001/02/21 13:46:53  adam
+ * C++ fixes.
+ *
+ * Revision 1.35  2000/11/27 15:17:40  adam
  * Using SSLeay_add_all_algorithms instead of OpenSSL_add_all_algorithms.
  *
  * Revision 1.34  2000/11/23 10:58:32  adam
@@ -211,6 +235,7 @@ int tcpip_bind(COMSTACK h, void *address, int mode);
 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
                 int (*check_ip)(void *cd, const char *a, int len, int type),
                 void *cd);
+int static tcpip_set_blocking(COMSTACK p, int blocking);
 
 #if HAVE_OPENSSL_SSL_H
 int ssl_get(COMSTACK h, char **buf, int *bufsize);
@@ -333,8 +358,9 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp)
     p->f_accept = tcpip_accept;
     p->f_addrstr = tcpip_addrstr;
     p->f_straddr = tcpip_straddr;
+    p->f_set_blocking = tcpip_set_blocking;
 
-    p->state = new_socket ? CS_UNBND : CS_IDLE; /* state of line */
+    p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
     p->event = CS_NONE;
     p->cerrno = 0;
     p->stackerr = 0;
@@ -467,7 +493,7 @@ int tcpip_connect(COMSTACK h, void *address)
 
     TRC(fprintf(stderr, "tcpip_connect\n"));
     h->io_pending = 0;
-    if (h->state == CS_UNBND)
+    if (h->state == CS_ST_UNBND)
     {
        r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
        if (r < 0)
@@ -475,23 +501,27 @@ int tcpip_connect(COMSTACK h, void *address)
 #ifdef WIN32
            if (WSAGetLastError() == WSAEWOULDBLOCK)
            {
-               h->state = CS_CONNECTING;
+               h->event = CS_CONNECT;
+               h->state = CS_ST_CONNECTING;
                h->io_pending = CS_WANT_WRITE;
                return 1;
            }
 #else
            if (errno == EINPROGRESS)
            {
-               h->state = CS_CONNECTING;
+               h->event = CS_CONNECT;
+               h->state = CS_ST_CONNECTING;
                h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
                return 1;
            }
 #endif
+           h->cerrno = CSYSERR;
            return -1;
        }
-       h->state = CS_CONNECTING;
+       h->event = CS_CONNECT;
+       h->state = CS_ST_CONNECTING;
     }
-    if (h->state != CS_CONNECTING)
+    if (h->state != CS_ST_CONNECTING)
     {
         h->cerrno = CSOUTSTATE;
        return -1;
@@ -522,21 +552,53 @@ int tcpip_connect(COMSTACK h, void *address)
                h->io_pending = CS_WANT_WRITE;
                return 1;
            }
+           h->cerrno = CSERRORSSL;
            return -1;
        }
     }
 #endif
-    h->state = CS_DATAXFER;
+    h->event = CS_DATA;
+    h->state = CS_ST_DATAXFER;
     return 0;
 }
 
 /*
  * nop
  */
-int tcpip_rcvconnect(COMSTACK h)
+int tcpip_rcvconnect(COMSTACK cs)
 {
     TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
-    return 0;
+
+    if (cs->event == CS_CONNECT)
+    {
+       int fd = cs->iofile;
+       fd_set input, output;
+       struct timeval tv;
+       int r;
+       
+       tv.tv_sec = 0;
+       tv.tv_usec = 1;
+       
+       FD_ZERO(&input);
+       FD_ZERO(&output);
+       FD_SET (fd, &input);
+       FD_SET (fd, &output);
+       
+       r = select (fd+1, &input, &output, 0, &tv);
+       if (r > 0)
+       {
+           if (FD_ISSET(cs->iofile, &output))
+           {
+               cs->event = CS_DATA;
+               return 0;   /* write OK, we're OK */
+           }
+           else
+               return -1;  /* an error, for sure */
+       }
+       else if (r == 0)
+           return 0;  /* timeout - incomplete */
+    }
+    return -1;    /* wrong state or bad select */
 }
 
 #define CERTF "ztest.pem"
@@ -588,13 +650,15 @@ int tcpip_bind(COMSTACK h, void *address, int mode)
 #else
     TRC (fprintf (stderr, "tcpip_bind\n"));
 #endif
+#ifndef WIN32
     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
        &one, sizeof(one)) < 0)
     {
         h->cerrno = CSYSERR;
         return -1;
     }
-    if (bind(h->iofile, addr, sizeof(struct sockaddr_in)) < 0)
+#endif
+    if (bind(h->iofile, addr, sizeof(struct sockaddr_in)))
     {
         h->cerrno = CSYSERR;
         return -1;
@@ -604,7 +668,8 @@ int tcpip_bind(COMSTACK h, void *address, int mode)
         h->cerrno = CSYSERR;
         return -1;
     }
-    h->state = CS_IDLE;
+    h->state = CS_ST_IDLE;
+    h->event = CS_LISTEN;
     return 0;
 }
 
@@ -613,10 +678,14 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
                 void *cd)
 {
     struct sockaddr_in addr;
+#ifdef __cplusplus
+    socklen_t len = sizeof(addr);
+#else
     int len = sizeof(addr);
+#endif
 
     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
-    if (h->state != CS_IDLE)
+    if (h->state != CS_ST_IDLE)
     {
         h->cerrno = CSOUTSTATE;
         return -1;
@@ -628,7 +697,12 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
 #ifdef WIN32
            WSAGetLastError() == WSAEWOULDBLOCK
 #else
-           errno == EWOULDBLOCK
+           errno == EWOULDBLOCK 
+#ifdef EAGAIN
+#if EAGAIN != EWOULDBLOCK
+            || errno == EAGAIN
+#endif
+#endif
 #endif
            )
            h->cerrno = CSNODATA;
@@ -652,7 +726,7 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
        h->newfd = -1;
        return -1;
     }
-    h->state = CS_INCON;
+    h->state = CS_ST_INCON;
     return 0;
 }
 
@@ -665,7 +739,7 @@ COMSTACK tcpip_accept(COMSTACK h)
 #endif
 
     TRC(fprintf(stderr, "tcpip_accept\n"));
-    if (h->state == CS_INCON)
+    if (h->state == CS_ST_INCON)
     {
        if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
        {
@@ -723,8 +797,8 @@ COMSTACK tcpip_accept(COMSTACK h)
        state->altsize = state->altlen = 0;
        state->towrite = state->written = -1;
        state->complete = st->complete;
-       cnew->state = CS_ACCEPT;
-       h->state = CS_IDLE;
+       cnew->state = CS_ST_ACCEPT;
+       h->state = CS_ST_IDLE;
        
 #if HAVE_OPENSSL_SSL_H
        state->ctx = st->ctx;
@@ -738,7 +812,7 @@ COMSTACK tcpip_accept(COMSTACK h)
 #endif
        h = cnew;
     }
-    if (h->state == CS_ACCEPT)
+    if (h->state == CS_ST_ACCEPT)
     {
 #if HAVE_OPENSSL_SSL_H
        tcpip_state *state = (tcpip_state *)h->cprivate;
@@ -773,7 +847,8 @@ COMSTACK tcpip_accept(COMSTACK h)
         return 0;
     }
     h->io_pending = 0;
-    h->state = CS_DATAXFER;
+    h->state = CS_ST_DATAXFER;
+    h->event = CS_DATA;
     return h;
 }
 
@@ -828,10 +903,13 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize)
            else
                return -1;
 #else
-           if (errno == EWOULDBLOCK
-#ifdef EINPROGRESS
-               || errno == EINPROGRESS
+           if (errno == EWOULDBLOCK 
+#ifdef EAGAIN   
+#if EAGAIN != EWOULDBLOCK
+                || errno == EAGAIN
+#endif
 #endif
+               || errno == EINPROGRESS
                )
            {
                h->io_pending = CS_WANT_READ;
@@ -929,6 +1007,7 @@ int ssl_get(COMSTACK h, char **buf, int *bufsize)
            }
            if (res == 0)
                return 0;
+           h->cerrno = CSERRORSSL;
            return -1;
        }
        hasread += res;
@@ -971,6 +1050,7 @@ int tcpip_put(COMSTACK h, char *buf, int size)
 
     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
     h->io_pending = 0;
+    h->event = CS_DATA;
     if (state->towrite < 0)
     {
         state->towrite = size;
@@ -983,14 +1063,26 @@ int tcpip_put(COMSTACK h, char *buf, int size)
     }
     while (state->towrite > state->written)
     {
-       if ((res = send(h->iofile, buf + state->written, size -
-                       state->written, 0)) < 0)
+       if ((res =
+            send(h->iofile, buf + state->written, size -
+                 state->written, 
+#ifdef MSG_NOSIGNAL
+                 MSG_NOSIGNAL
+#else
+                 0
+#endif
+                )) < 0)
        {
            if (
 #ifdef WIN32
                WSAGetLastError() == WSAEWOULDBLOCK
 #else
-               errno == EAGAIN
+               errno == EWOULDBLOCK 
+#ifdef EAGAIN
+#if EAGAIN != EWOULDBLOCK
+             || errno == EAGAIN
+#endif
+#endif
 #endif
                )
            {
@@ -1024,6 +1116,7 @@ int ssl_put(COMSTACK h, char *buf, int size)
 
     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
     h->io_pending = 0;
+    h->event = CS_DATA;
     if (state->towrite < 0)
     {
         state->towrite = size;
@@ -1053,6 +1146,7 @@ int ssl_put(COMSTACK h, char *buf, int size)
                yaz_log (LOG_LOG, "SSL_write. want_write");
                return 1;
            }
+           h->cerrno = CSERRORSSL;
            return -1;
        }
        state->written += res;
@@ -1127,3 +1221,26 @@ char *tcpip_addrstr(COMSTACK h)
 #endif
     return buf;
 }
+
+int static tcpip_set_blocking(COMSTACK p, int blocking)
+{
+    unsigned long flag;
+    
+    if (p->blocking == blocking)
+       return 1;
+#ifdef WIN32
+    flag = 1;
+    if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
+       return 0;
+#else
+    flag = fcntl(p->iofile, F_GETFL, 0);
+    if(!blocking)
+       flag = flag & ~O_NONBLOCK;
+    else
+        flag = flag | O_NONBLOCK;
+    if (fcntl(p->iofile, F_SETFL, flag) < 0)
+       return 0;
+#endif
+    p->blocking = blocking;
+    return 1;
+}