Use getaddrinfo on Windows too
[yaz-moved-to-github.git] / src / tcpip.c
index db0e834..72faa78 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 1995-2005, Index Data ApS
+ * Copyright (C) 1995-2006, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: tcpip.c,v 1.16 2005-06-25 15:46:06 adam Exp $
+ * $Id: tcpip.c,v 1.24 2006-08-30 19:26:43 adam Exp $
  */
 /**
  * \file tcpip.c
@@ -26,7 +26,9 @@
 #endif
 
 #ifdef WIN32
-#include <winsock.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define HAVE_GETADDRINFO 1
 #else
 #include <netinet/in.h>
 #include <netdb.h>
@@ -94,7 +96,11 @@ 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. */
+#if HAVE_GETADDRINFO
+    struct addrinfo *res;
+#else
     struct sockaddr_in addr;  /* returned by cs_straddr */
+#endif
     char buf[128]; /* returned by cs_addrstr */
 #if HAVE_OPENSSL_SSL_H
     SSL_CTX *ctx;       /* current CTX. */
@@ -187,6 +193,7 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp)
     p->f_addrstr = tcpip_addrstr;
     p->f_straddr = tcpip_straddr;
     p->f_set_blocking = tcpip_set_blocking;
+    p->max_recv_bytes = 5000000;
 
     p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
     p->event = CS_NONE;
@@ -200,6 +207,9 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp)
     strcpy(sp->cert_fname, "yaz.pem");
 #endif
 
+#if HAVE_GETADDRINFO
+    sp->res = 0;
+#endif
     sp->altbuf = 0;
     sp->altsize = sp->altlen = 0;
     sp->towrite = sp->written = -1;
@@ -236,20 +246,64 @@ COMSTACK ssl_type(int s, int blocking, int protocol, void *vp)
 }
 #endif
 
+#if HAVE_GETADDRINFO
+/* resolve using getaddrinfo */
+struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port)
+{
+    struct addrinfo hints, *res;
+    int error;
+    char host[512], *p;
+
+    hints.ai_flags = 0;
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = 0;
+    hints.ai_addrlen        = 0;
+    hints.ai_addr           = NULL;
+    hints.ai_canonname      = NULL;
+    hints.ai_next           = NULL;
+
+    strncpy(host, str, sizeof(host)-1);
+    host[sizeof(host)-1] = 0;
+    if ((p = strchr(host, '/')))
+        *p = 0;
+    if ((p = strchr(host, ':')))
+    {
+        *p = '\0';
+        port = p+1;
+    }
+
+    if (!strcmp("@", host))
+    {
+        hints.ai_flags = AI_PASSIVE;
+        error = getaddrinfo(0, port, &hints, &res);
+    }
+    else
+    {
+        error = getaddrinfo(host, port, &hints, &res);
+    }
+    if (error)
+        return 0;
+    return res;
+}
+
+#endif
+/* gethostbyname .. old systems */
 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
                        int default_port)
 {
     struct hostent *hp;
     char *p, buf[512];
     short int port = default_port;
-    unsigned tmpadd;
-
-    if (!tcpip_init ())
-        return 0;
+#ifdef WIN32
+    unsigned long tmpadd;
+#else
+    in_addr_t tmpadd;
+#endif
     TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
     add->sin_family = AF_INET;
-    strncpy(buf, str, 511);
-    buf[511] = 0;
+    strncpy(buf, str, sizeof(buf)-1);
+    buf[sizeof(buf)-1] = 0;
     if ((p = strchr(buf, '/')))
         *p = 0;
     if ((p = strchr(buf, ':')))
@@ -259,38 +313,54 @@ int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
     }
     add->sin_port = htons(port);
     if (!strcmp("@", buf))
+    {
         add->sin_addr.s_addr = INADDR_ANY;
+    }
+    else if ((tmpadd = inet_addr(buf)) != -1)
+    {
+        memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+    }
     else if ((hp = gethostbyname(buf)))
+    {
         memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
                sizeof(struct in_addr));
-    else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
-        memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+    }
     else
         return 0;
     return 1;
 }
 
+
+#if HAVE_GETADDRINFO
 void *tcpip_straddr(COMSTACK h, const char *str)
 {
     tcpip_state *sp = (tcpip_state *)h->cprivate;
-    int port = 210;
+    const char *port = "210";
+    if (h->protocol == PROTO_HTTP)
+        port = "80";
+    if (!tcpip_init ())
+        return 0;
 
+    if (sp->res)
+        freeaddrinfo(sp->res);
+    sp->res = tcpip_getaddrinfo(str, port);
+    return sp->res;
+}
+#else
+void *tcpip_straddr(COMSTACK h, const char *str)
+{
+    tcpip_state *sp = (tcpip_state *)h->cprivate;
+    int port = 210;
     if (h->protocol == PROTO_HTTP)
         port = 80;
 
+    if (!tcpip_init ())
+        return 0;
     if (!tcpip_strtoaddr_ex (str, &sp->addr, port))
         return 0;
     return &sp->addr;
 }
-
-struct sockaddr_in *tcpip_strtoaddr(const char *str)
-{
-    static struct sockaddr_in add;
-    
-    if (!tcpip_strtoaddr_ex (str, &add, 210))
-        return 0;
-    return &add;
-}
+#endif
 
 int tcpip_more(COMSTACK h)
 {
@@ -307,7 +377,11 @@ int tcpip_more(COMSTACK h)
  */
 int tcpip_connect(COMSTACK h, void *address)
 {
-    struct sockaddr_in *add = (struct sockaddr_in *)address;
+#if HAVE_GETADDRINFO
+    struct addrinfo *ai = (struct addrinfo *) address; 
+#else
+    struct sockaddr_in *add = (struct sockaddr_in *) address;
+#endif
     int r;
 #ifdef __sun__
     int recbuflen;
@@ -346,7 +420,12 @@ int tcpip_connect(COMSTACK h, void *address)
     TRC(fprintf( stderr, "New Size of TCP Receive Buffer = %d\n",
                  recbuflen ));
 #endif
+
+#if HAVE_GETADDRINFO
+    r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen);
+#else
     r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
+#endif
     if (r < 0)
     {
 #ifdef WIN32
@@ -464,7 +543,12 @@ static void tcpip_setsockopt (int fd)
 
 static int tcpip_bind(COMSTACK h, void *address, int mode)
 {
+    int r;
+#if HAVE_GETADDRINFO
+    struct addrinfo *ai = (struct addrinfo *)address;
+#else
     struct sockaddr *addr = (struct sockaddr *)address;
+#endif
 #ifdef WIN32
     BOOL one = 1;
 #else
@@ -490,8 +574,7 @@ static int tcpip_bind(COMSTACK h, void *address, int mode)
         if (sp->ctx_alloc)
         {
             int res;
-            res = SSL_CTX_use_certificate_file (sp->ctx, sp->cert_fname,
-                                                SSL_FILETYPE_PEM);
+            res = SSL_CTX_use_certificate_chain_file(sp->ctx, sp->cert_fname);
             if (res <= 0)
             {
                 ERR_print_errors_fp(stderr);
@@ -529,12 +612,18 @@ static int tcpip_bind(COMSTACK h, void *address, int mode)
     }
 #endif
     tcpip_setsockopt(h->iofile);
-    if (bind(h->iofile, addr, sizeof(struct sockaddr_in)))
+#if HAVE_GETADDRINFO
+    r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
+#else
+    r = bind(h->iofile, addr, sizeof(struct sockaddr_in));
+#endif
+    if (r)
     {
         h->cerrno = CSYSERR;
         return -1;
     }
-    if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
+    /* Allow a maximum-sized backlog of waiting-to-connect clients */
+    if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
     {
         h->cerrno = CSYSERR;
         return -1;
@@ -751,11 +840,17 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize)
         if (!*bufsize)
         {
             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
+            {
+                h->cerrno = CSYSERR;
                 return -1;
+            }
         }
         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
+            {
+                h->cerrno = CSYSERR;
                 return -1;
+            }
 #ifdef __sun__
         yaz_set_errno( 0 );
         /* unfortunatly, sun sometimes forgets to set errno in recv
@@ -800,6 +895,11 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize)
         else if (!res)
             return hasread;
         hasread += res;
+        if (hasread > h->max_recv_bytes)
+        {
+            h->cerrno = CSBUFSIZE;
+            return -1;
+        }
     }
     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
                   hasread, berlen));
@@ -1066,6 +1166,10 @@ int tcpip_close(COMSTACK h)
     if (sp->ctx_alloc)
         SSL_CTX_free (sp->ctx_alloc);
 #endif
+#if HAVE_GETADDRINFO
+    if (sp->res)
+        freeaddrinfo(sp->res);
+#endif
     xfree(sp);
     xfree(h);
     return 0;