don't call gethostbyname if OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL is set
[openssl.git] / apps / s_socket.c
index 1d8587f1f5c11853684ca5e952d1997ad5180c1a..d83eecb6dedfae47b6a4f2175f533f22b59c8292 100644 (file)
@@ -1,4 +1,4 @@
-/* apps/s_socket.c */
+/* apps/s_socket.c -  socket-related functions used by s_client and s_server */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
  * [including the GNU Public Licence.]
  */
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
 /* With IPv6, it looks like Digital has mixed up the proper order of
    recursive header file inclusion, resulting in the compiler complaining
    that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
    is needed to have fileno() declared correctly...  So let's define u_int */
-#if defined(__DECC) && !defined(__U_INT)
+#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
 #define __U_INT
 typedef unsigned int u_int;
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
 #define USE_SOCKETS
 #define NON_MAIN
 #include "apps.h"
@@ -78,27 +79,45 @@ typedef unsigned int u_int;
 #include "s_apps.h"
 #include <openssl/ssl.h>
 
-#if (__VMS_VER < 70000000) /* FIONBIO used as a switch to enable ioctl,
-                             and that isn't in VMS < 7.0 */
-#undef FIONBIO
+#ifdef FLAT_INC
+#include "e_os.h"
+#else
+#include "../e_os.h"
 #endif
-#ifdef VMS /* for vfork() */
-#include <processes.h>
+
+#ifndef OPENSSL_NO_SOCK
+
+#if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
+#include "netdb.h"
 #endif
 
 static struct hostent *GetHostByName(char *name);
-int sock_init(void );
-#ifdef WIN16
+#if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
+static void ssl_sock_cleanup(void);
+#endif
+static int ssl_sock_init(void);
+static int init_client_ip(int *sock, const unsigned char ip[4], int port,
+                         int type);
+static int init_server(int *sock, int port, int type);
+static int init_server_long(int *sock, int port,char *ip, int type);
+static int do_accept(int acc_sock, int *sock, char **host);
+static int host_ip(char *str, unsigned char ip[4]);
+
+#ifdef OPENSSL_SYS_WIN16
 #define SOCKET_PROTOCOL        0 /* more microsoft stupidity */
 #else
 #define SOCKET_PROTOCOL        IPPROTO_TCP
 #endif
 
-#ifdef WINDOWS
+#if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
+static int wsa_init_done=0;
+#endif
+
+#ifdef OPENSSL_SYS_WINDOWS
 static struct WSAData wsa_state;
 static int wsa_init_done=0;
 
-#ifdef WIN16
+#ifdef OPENSSL_SYS_WIN16
 static HWND topWnd=0;
 static FARPROC lpTopWndProc=NULL;
 static FARPROC lpTopHookProc=NULL;
@@ -114,7 +133,7 @@ static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
                case WM_DESTROY:
                case WM_CLOSE:
                        SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
-                       sock_cleanup();
+                       ssl_sock_cleanup();
                        break;
                        }
                }
@@ -127,30 +146,46 @@ static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
        return(FALSE);
        }
 
-#endif /* WIN32 */
-#endif /* WINDOWS */
+#endif /* OPENSSL_SYS_WIN32 */
+#endif /* OPENSSL_SYS_WINDOWS */
 
-void sock_cleanup(void)
+#ifdef OPENSSL_SYS_WINDOWS
+static void ssl_sock_cleanup(void)
        {
-#ifdef WINDOWS
        if (wsa_init_done)
                {
                wsa_init_done=0;
+#ifndef OPENSSL_SYS_WINCE
                WSACancelBlockingCall();
+#endif
+               WSACleanup();
+               }
+       }
+#elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
+static void sock_cleanup(void)
+    {
+    if (wsa_init_done)
+        {
+        wsa_init_done=0;
                WSACleanup();
                }
-#endif
        }
+#endif
 
-int sock_init(void)
+static int ssl_sock_init(void)
        {
-#ifdef WINDOWS
+#ifdef WATT32
+       extern int _watt_do_exit;
+       _watt_do_exit = 0;
+       if (sock_init())
+               return (0);
+#elif defined(OPENSSL_SYS_WINDOWS)
        if (!wsa_init_done)
                {
                int err;
          
 #ifdef SIGINT
-               signal(SIGINT,(void (*)(int))sock_cleanup);
+               signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
 #endif
                wsa_init_done=1;
                memset(&wsa_state,0,sizeof(wsa_state));
@@ -161,38 +196,57 @@ int sock_init(void)
                        return(0);
                        }
 
-#ifdef WIN16
+#ifdef OPENSSL_SYS_WIN16
                EnumTaskWindows(GetCurrentTask(),enumproc,0L);
                lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
                lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
 
                SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
-#endif /* WIN16 */
+#endif /* OPENSSL_SYS_WIN16 */
                }
-#endif /* WINDOWS */
+#elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
+   WORD wVerReq;
+   WSADATA wsaData;
+   int err;
+
+   if (!wsa_init_done)
+      {
+   
+# ifdef SIGINT
+      signal(SIGINT,(void (*)(int))sock_cleanup);
+# endif
+
+      wsa_init_done=1;
+      wVerReq = MAKEWORD( 2, 0 );
+      err = WSAStartup(wVerReq,&wsaData);
+      if (err != 0)
+         {
+         BIO_printf(bio_err,"unable to start WINSOCK2, error code=%d\n",err);
+         return(0);
+         }
+      }
+#endif /* OPENSSL_SYS_WINDOWS */
        return(1);
        }
 
-int init_client(int *sock, char *host, int port)
+int init_client(int *sock, char *host, int port, int type)
        {
        unsigned char ip[4];
-       short p=0;
 
+       ip[0] = ip[1] = ip[2] = ip[3] = 0;
        if (!host_ip(host,&(ip[0])))
-               {
-               return(0);
-               }
-       if (p != 0) port=p;
-       return(init_client_ip(sock,ip,port));
+               return 0;
+       return init_client_ip(sock,ip,port,type);
        }
 
-int init_client_ip(int *sock, unsigned char ip[4], int port)
+static int init_client_ip(int *sock, const unsigned char ip[4], int port,
+                         int type)
        {
        unsigned long addr;
        struct sockaddr_in them;
        int s,i;
 
-       if (!sock_init()) return(0);
+       if (!ssl_sock_init()) return(0);
 
        memset((char *)&them,0,sizeof(them));
        them.sin_family=AF_INET;
@@ -204,111 +258,65 @@ int init_client_ip(int *sock, unsigned char ip[4], int port)
                ((unsigned long)ip[3]);
        them.sin_addr.s_addr=htonl(addr);
 
-       s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+       if (type == SOCK_STREAM)
+               s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+       else /* ( type == SOCK_DGRAM) */
+               s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+                       
        if (s == INVALID_SOCKET) { perror("socket"); return(0); }
 
-       i=0;
-       i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
-       if (i < 0) { perror("keepalive"); return(0); }
-
-       if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
-               { close(s); perror("connect"); return(0); }
-       *sock=s;
-       return(1);
-       }
-
-int nbio_sock_error(int sock)
-       {
-       int j,i;
-       int size;
-
-       size=sizeof(int);
-       /* Note: under VMS with SOCKETSHR the third parameter is currently
-        * of type (int *) whereas under other systems it is (void *) if
-        * you don't have a cast it will choke the compiler: if you do
-        * have a cast then you can either go for (int *) or (void *).
-        */
-       i=getsockopt(sock,SOL_SOCKET,SO_ERROR,(char *)&j,(void *)&size);
-       if (i < 0)
-               return(1);
-       else
-               return(j);
-       }
-
-int nbio_init_client_ip(int *sock, unsigned char ip[4], int port)
-       {
-       unsigned long addr;
-       struct sockaddr_in them;
-       int s,i;
-
-       if (!sock_init()) return(0);
-
-       memset((char *)&them,0,sizeof(them));
-       them.sin_family=AF_INET;
-       them.sin_port=htons((unsigned short)port);
-       addr=   (unsigned long)
-               ((unsigned long)ip[0]<<24L)|
-               ((unsigned long)ip[1]<<16L)|
-               ((unsigned long)ip[2]<< 8L)|
-               ((unsigned long)ip[3]);
-       them.sin_addr.s_addr=htonl(addr);
-
-       if (*sock <= 0)
+#if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
+       if (type == SOCK_STREAM)
                {
-               unsigned long l=1;
-
-               s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
-               if (s == INVALID_SOCKET) { perror("socket"); return(0); }
-
                i=0;
                i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
                if (i < 0) { perror("keepalive"); return(0); }
-               *sock=s;
-
-#ifdef FIONBIO
-               BIO_socket_ioctl(s,FIONBIO,&l);
-#endif
                }
-       else
-               s= *sock;
+#endif
 
-       i=connect(s,(struct sockaddr *)&them,sizeof(them));
-       if (i == INVALID_SOCKET)
-               {
-               if (BIO_sock_should_retry(i))
-                       return(-1);
-               else
-                       return(0);
-               }
-       else
-               return(1);
+       if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
+               { closesocket(s); perror("connect"); return(0); }
+       *sock=s;
+       return(1);
        }
 
-int do_server(int port, int *ret, int (*cb)(), char *context)
+int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), unsigned char *context, int naccept)
        {
        int sock;
-       char *name;
-       int accept_socket;
+       char *name = NULL;
+       int accept_socket = 0;
        int i;
 
-       if (!init_server(&accept_socket,port)) return(0);
+       if (!init_server(&accept_socket,port,type)) return(0);
 
        if (ret != NULL)
                {
                *ret=accept_socket;
                /* return(1);*/
                }
-       for (;;)
-               {
-               if (do_accept(accept_socket,&sock,&name) == 0)
+       for (;;)
+               {
+               if (type==SOCK_STREAM)
                        {
-                       SHUTDOWN(accept_socket);
-                       return(0);
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+                       if (do_accept(accept_socket,&sock,NULL) == 0)
+#else
+                       if (do_accept(accept_socket,&sock,&name) == 0)
+#endif
+                               {
+                               SHUTDOWN(accept_socket);
+                               return(0);
+                               }
                        }
+               else
+                       sock = accept_socket;
                i=(*cb)(name,sock, context);
-               if (name != NULL) Free(name);
-               SHUTDOWN2(sock);
-               if (i < 0)
+               if (name != NULL) OPENSSL_free(name);
+               if (type==SOCK_STREAM)
+                       SHUTDOWN2(sock);
+               if (naccept != -1)
+                       naccept--;
+               if (i < 0 || naccept == 0)
                        {
                        SHUTDOWN2(accept_socket);
                        return(i);
@@ -316,13 +324,13 @@ int do_server(int port, int *ret, int (*cb)(), char *context)
                }
        }
 
-int init_server_long(int *sock, int port, char *ip)
+static int init_server_long(int *sock, int port, char *ip, int type)
        {
        int ret=0;
        struct sockaddr_in server;
-       int s= -1,i;
+       int s= -1;
 
-       if (!sock_init()) return(0);
+       if (!ssl_sock_init()) return(0);
 
        memset((char *)&server,0,sizeof(server));
        server.sin_family=AF_INET;
@@ -336,7 +344,11 @@ int init_server_long(int *sock, int port, char *ip)
 #else
                memcpy(&server.sin_addr,ip,4);
 #endif
-       s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+       
+               if (type == SOCK_STREAM)
+                       s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+               else /* type == SOCK_DGRAM */
+                       s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
 
        if (s == INVALID_SOCKET) goto err;
 #if defined SOL_SOCKET && defined SO_REUSEADDR
@@ -348,14 +360,13 @@ int init_server_long(int *sock, int port, char *ip)
 #endif
        if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
                {
-#ifndef WINDOWS
+#ifndef OPENSSL_SYS_WINDOWS
                perror("bind");
 #endif
                goto err;
                }
        /* Make it 128 for linux */
-       if (listen(s,128) == -1) goto err;
-       i=0;
+       if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
        *sock=s;
        ret=1;
 err:
@@ -366,28 +377,28 @@ err:
        return(ret);
        }
 
-int init_server(int *sock, int port)
+static int init_server(int *sock, int port, int type)
        {
-       return(init_server_long(sock, port, NULL));
+       return(init_server_long(sock, port, NULL, type));
        }
 
-int do_accept(int acc_sock, int *sock, char **host)
+static int do_accept(int acc_sock, int *sock, char **host)
        {
-       int ret,i;
+       int ret;
        struct hostent *h1,*h2;
        static struct sockaddr_in from;
        int len;
 /*     struct linger ling; */
 
-       if (!sock_init()) return(0);
+       if (!ssl_sock_init()) return(0);
 
-#ifndef WINDOWS
+#ifndef OPENSSL_SYS_WINDOWS
 redoit:
 #endif
 
        memset((char *)&from,0,sizeof(from));
        len=sizeof(from);
-       /* Note: under VMS with SOCKETSHR the third parameter is currently
+       /* Note: under VMS with SOCKETSHR the fourth parameter is currently
         * of type (int *) whereas under other systems it is (void *) if
         * you don't have a cast it will choke the compiler: if you do
         * have a cast then you can either go for (int *) or (void *).
@@ -395,7 +406,8 @@ redoit:
        ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
        if (ret == INVALID_SOCKET)
                {
-#ifdef WINDOWS
+#if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
+               int i;
                i=WSAGetLastError();
                BIO_printf(bio_err,"accept error %d\n",i);
 #else
@@ -437,12 +449,12 @@ redoit:
                }
        else
                {
-               if ((*host=(char *)Malloc(strlen(h1->h_name)+1)) == NULL)
+               if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
                        {
-                       perror("Malloc");
+                       perror("OPENSSL_malloc");
                        return(0);
                        }
-               strcpy(*host,h1->h_name);
+               BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
 
                h2=GetHostByName(*host);
                if (h2 == NULL)
@@ -450,7 +462,6 @@ redoit:
                        BIO_printf(bio_err,"gethostbyname failure\n");
                        return(0);
                        }
-               i=0;
                if (h2->h_addrtype != AF_INET)
                        {
                        BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
@@ -487,12 +498,12 @@ err:
        return(0);
        }
 
-int host_ip(char *str, unsigned char ip[4])
+static int host_ip(char *str, unsigned char ip[4])
        {
        unsigned int in[4]; 
        int i;
 
-       if (sscanf(str,"%d.%d.%d.%d",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
+       if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
                {
                for (i=0; i<4; i++)
                        if (in[i] > 255)
@@ -509,7 +520,7 @@ int host_ip(char *str, unsigned char ip[4])
                { /* do a gethostbyname */
                struct hostent *he;
 
-               if (!sock_init()) return(0);
+               if (!ssl_sock_init()) return(0);
 
                he=GetHostByName(str);
                if (he == NULL)
@@ -590,9 +601,12 @@ static struct hostent *GetHostByName(char *name)
                ret=gethostbyname(name);
                if (ret == NULL) return(NULL);
                /* else add to cache */
-               strncpy(ghbn_cache[lowi].name,name,128);
-               memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
-               ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
+               if(strlen(name) < sizeof ghbn_cache[0].name)
+                       {
+                       strcpy(ghbn_cache[lowi].name,name);
+                       memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
+                       ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
+                       }
                return(ret);
                }
        else
@@ -604,68 +618,4 @@ static struct hostent *GetHostByName(char *name)
                }
        }
 
-#ifndef MSDOS
-int spawn(int argc, char **argv, int *in, int *out)
-       {
-       int pid;
-#define CHILD_READ     p1[0]
-#define CHILD_WRITE    p2[1]
-#define PARENT_READ    p2[0]
-#define PARENT_WRITE   p1[1]
-       int p1[2],p2[2];
-
-       if ((pipe(p1) < 0) || (pipe(p2) < 0)) return(-1);
-
-#ifdef VMS
-       if ((pid=vfork()) == 0)
-#else
-       if ((pid=fork()) == 0)
-#endif
-               { /* child */
-               if (dup2(CHILD_WRITE,fileno(stdout)) < 0)
-                       perror("dup2");
-               if (dup2(CHILD_WRITE,fileno(stderr)) < 0)
-                       perror("dup2");
-               if (dup2(CHILD_READ,fileno(stdin)) < 0)
-                       perror("dup2");
-               close(CHILD_READ); 
-               close(CHILD_WRITE);
-
-               close(PARENT_READ);
-               close(PARENT_WRITE);
-               execvp(argv[0],argv);
-               perror("child");
-               exit(1);
-               }
-
-       /* parent */
-       *in= PARENT_READ;
-       *out=PARENT_WRITE;
-       close(CHILD_READ);
-       close(CHILD_WRITE);
-       return(pid);
-       }
-#endif /* MSDOS */
-
-
-#ifdef undef
-       /* Turn on synchronous sockets so that we can do a WaitForMultipleObjects
-        * on sockets */
-       {
-       SOCKET s;
-       int optionValue = SO_SYNCHRONOUS_NONALERT;
-       int err;
-
-       err = setsockopt( 
-           INVALID_SOCKET, 
-           SOL_SOCKET, 
-           SO_OPENTYPE, 
-           (char *)&optionValue, 
-           sizeof(optionValue));
-       if (err != NO_ERROR) {
-       /* failed for some reason... */
-               BIO_printf(bio_err, "failed to setsockopt(SO_OPENTYPE, SO_SYNCHRONOUS_ALERT) - %d\n",
-                       WSAGetLastError());
-               }
-       }
 #endif