Link SSL with libyaz.la and yaz-client only.
[yaz-moved-to-github.git] / src / tcpip.c
index 45b2ad1..b992319 100644 (file)
@@ -1,8 +1,6 @@
-/*
- * Copyright (C) 1995-2006, Index Data ApS
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2008 Index Data
  * See the file LICENSE for details.
- *
- * $Id: tcpip.c,v 1.30 2006-09-15 09:06:28 adam Exp $
  */
 /**
  * \file tcpip.c
 #endif
 
 #ifdef WIN32
+
+/* VS 2003 or later has getaddrinfo; older versions do not */
 #include <winsock2.h>
+#if _MSC_VER >= 1300
 #include <ws2tcpip.h>
 #define HAVE_GETADDRINFO 1
 #else
+#define HAVE_GETADDRINFO 0
+#endif
+
+#else
 #include <netinet/in.h>
 #include <netdb.h>
 #include <arpa/inet.h>
@@ -39,9 +44,6 @@
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
@@ -58,6 +60,8 @@
 static int tcpip_close(COMSTACK h);
 static int tcpip_put(COMSTACK h, char *buf, int size);
 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
+static int tcpip_put_connect(COMSTACK h, char *buf, int size);
+static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize);
 static int tcpip_connect(COMSTACK h, void *address);
 static int tcpip_more(COMSTACK h);
 static int tcpip_rcvconnect(COMSTACK h);
@@ -95,7 +99,7 @@ typedef struct tcpip_state
 
     int written;  /* -1 if we aren't writing */
     int towrite;  /* to verify against user input */
-    int (*complete)(const unsigned char *buf, int len); /* length/comple. */
+    int (*complete)(const char *buf, int len); /* length/complete. */
 #if HAVE_GETADDRINFO
     struct addrinfo *ai;
 #else
@@ -108,6 +112,10 @@ typedef struct tcpip_state
     SSL *ssl;
     char cert_fname[256];
 #endif
+    char *connect_request_buf;
+    int connect_request_len;
+    char *connect_response_buf;
+    int connect_response_len;
 } tcpip_state;
 
 #ifdef WIN32
@@ -194,12 +202,38 @@ COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
     else
         sp->complete = cs_complete_auto;
 
+    sp->connect_request_buf = 0;
+    sp->connect_request_len = 0;
+    sp->connect_response_buf = 0;
+    sp->connect_response_len = 0;
+
     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
 
     return p;
 }
 
+COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
+                          const char *connect_host)
+{
+    COMSTACK p = tcpip_type(s, flags, protocol, 0);
+    if (!p)
+        return 0;
+    if (connect_host)
+    {
+        tcpip_state *sp = (tcpip_state *) p->cprivate;
+        sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 30);
+        sprintf(sp->connect_request_buf, "CONNECT %s HTTP/1.0\r\n\r\n",
+                connect_host);
+        sp->connect_request_len = strlen(sp->connect_request_buf);
+        p->f_put = tcpip_put_connect;
+        p->f_get = tcpip_get_connect;
+        sp->complete = cs_complete_auto_head; /* only want HTTP header */
+    }
+    return p;
+}
+
+
 #if HAVE_OPENSSL_SSL_H
 
 COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
@@ -370,8 +404,7 @@ int tcpip_more(COMSTACK h)
 {
     tcpip_state *sp = (tcpip_state *)h->cprivate;
     
-    return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
-        sp->altlen);
+    return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
 }
 
 /*
@@ -487,8 +520,8 @@ int tcpip_rcvconnect(COMSTACK h)
 #if HAVE_OPENSSL_SSL_H
     if (h->type == ssl_type && !sp->ctx)
     {
+        SSL_library_init();
         SSL_load_error_strings();
-        SSLeay_add_all_algorithms();
 
         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method());
         if (!sp->ctx)
@@ -565,7 +598,7 @@ static int tcpip_bind(COMSTACK h, void *address, int mode)
 #ifdef WIN32
     BOOL one = 1;
 #else
-    unsigned long one = 1;
+    int one = 1;
 #endif
 
 #if HAVE_GETADDRINFO
@@ -579,8 +612,8 @@ static int tcpip_bind(COMSTACK h, void *address, int mode)
 #if HAVE_OPENSSL_SSL_H
     if (h->type == ssl_type && !sp->ctx)
     {
+        SSL_library_init();
         SSL_load_error_strings();
-        SSLeay_add_all_algorithms();
 
         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method());
         if (!sp->ctx)
@@ -685,7 +718,15 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
             )
             h->cerrno = CSNODATA;
         else
+        {
+#ifdef WIN32
+            shutdown(h->iofile, SD_RECEIVE);
+#else
+            shutdown(h->iofile, SHUT_RD);
+#endif
+            listen(h->iofile, SOMAXCONN);
             h->cerrno = CSYSERR;
+        }
         return -1;
     }
     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
@@ -786,6 +827,8 @@ COMSTACK tcpip_accept(COMSTACK h)
             SSL_set_fd (state->ssl, cnew->iofile);
         }
 #endif
+        state->connect_request_buf = 0;
+        state->connect_response_buf = 0;
         h = cnew;
     }
     if (h->state == CS_ST_ACCEPT)
@@ -854,7 +897,7 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize)
         sp->altsize = tmpi;
     }
     h->io_pending = 0;
-    while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
+    while (!(berlen = (*sp->complete)(*buf, hasread)))
     {
         if (!*bufsize)
         {
@@ -985,7 +1028,7 @@ int ssl_get(COMSTACK h, char **buf, int *bufsize)
         sp->altsize = tmpi;
     }
     h->io_pending = 0;
-    while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
+    while (!(berlen = (*sp->complete)(*buf, hasread)))
     {
         if (!*bufsize)
         {
@@ -1201,6 +1244,8 @@ int tcpip_close(COMSTACK h)
     if (sp->ai)
         freeaddrinfo(sp->ai);
 #endif
+    xfree(sp->connect_request_buf);
+    xfree(sp->connect_response_buf);
     xfree(sp);
     xfree(h);
     return 0;
@@ -1368,6 +1413,38 @@ int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
 }
 #endif
 
+
+static int tcpip_put_connect(COMSTACK h, char *buf, int size)
+{
+    struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+
+    int r = tcpip_put(h, state->connect_request_buf,
+                      state->connect_request_len);
+    if (r == 0)
+    {
+        /* it's sent */
+        h->f_put = tcpip_put; /* switch to normal tcpip put */
+        r = tcpip_put(h, buf, size);
+    }
+    return r;
+}
+
+static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
+{
+    struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+    int r;
+
+    r = tcpip_get(h, &state->connect_response_buf, 
+                  &state->connect_response_len);
+    if (r < 1)
+        return r;
+    /* got the connect response completely */
+    state->complete = cs_complete_auto; /* switch to normal tcpip get */
+    h->f_get = tcpip_get;
+    return tcpip_get(h, buf, bufsize);
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 4