Main Page | Class List | Directories | File List | Class Members | File Members

s_socket.c

Go to the documentation of this file.
00001 /* apps/s_socket.c -  socket-related functions used by s_client and s_server */
00002 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
00003  * All rights reserved.
00004  *
00005  * This package is an SSL implementation written
00006  * by Eric Young (eay@cryptsoft.com).
00007  * The implementation was written so as to conform with Netscapes SSL.
00008  * 
00009  * This library is free for commercial and non-commercial use as long as
00010  * the following conditions are aheared to.  The following conditions
00011  * apply to all code found in this distribution, be it the RC4, RSA,
00012  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
00013  * included with this distribution is covered by the same copyright terms
00014  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
00015  * 
00016  * Copyright remains Eric Young's, and as such any Copyright notices in
00017  * the code are not to be removed.
00018  * If this package is used in a product, Eric Young should be given attribution
00019  * as the author of the parts of the library used.
00020  * This can be in the form of a textual message at program startup or
00021  * in documentation (online or textual) provided with the package.
00022  * 
00023  * Redistribution and use in source and binary forms, with or without
00024  * modification, are permitted provided that the following conditions
00025  * are met:
00026  * 1. Redistributions of source code must retain the copyright
00027  *    notice, this list of conditions and the following disclaimer.
00028  * 2. Redistributions in binary form must reproduce the above copyright
00029  *    notice, this list of conditions and the following disclaimer in the
00030  *    documentation and/or other materials provided with the distribution.
00031  * 3. All advertising materials mentioning features or use of this software
00032  *    must display the following acknowledgement:
00033  *    "This product includes cryptographic software written by
00034  *     Eric Young (eay@cryptsoft.com)"
00035  *    The word 'cryptographic' can be left out if the rouines from the library
00036  *    being used are not cryptographic related :-).
00037  * 4. If you include any Windows specific code (or a derivative thereof) from 
00038  *    the apps directory (application code) you must include an acknowledgement:
00039  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
00040  * 
00041  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
00042  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00043  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00044  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00045  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00046  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00047  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00048  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00049  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00050  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00051  * SUCH DAMAGE.
00052  * 
00053  * The licence and distribution terms for any publically available version or
00054  * derivative of this code cannot be changed.  i.e. this code cannot simply be
00055  * copied and put under another distribution licence
00056  * [including the GNU Public Licence.]
00057  */
00058 
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <string.h>
00062 #include <errno.h>
00063 #include <signal.h>
00064 
00065 /* With IPv6, it looks like Digital has mixed up the proper order of
00066    recursive header file inclusion, resulting in the compiler complaining
00067    that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
00068    is needed to have fileno() declared correctly...  So let's define u_int */
00069 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
00070 #define __U_INT
00071 typedef unsigned int u_int;
00072 #endif
00073 
00074 #define USE_SOCKETS
00075 #define NON_MAIN
00076 #include "apps.h"
00077 #undef USE_SOCKETS
00078 #undef NON_MAIN
00079 #include "s_apps.h"
00080 #include <openssl/ssl.h>
00081 
00082 #ifdef FLAT_INC
00083 #include "e_os.h"
00084 #else
00085 #include "../e_os.h"
00086 #endif
00087 
00088 #ifndef OPENSSL_NO_SOCK
00089 
00090 #if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
00091 #include "netdb.h"
00092 #endif
00093 
00094 static struct hostent *GetHostByName(char *name);
00095 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
00096 static void ssl_sock_cleanup(void);
00097 #endif
00098 static int ssl_sock_init(void);
00099 static int init_client_ip(int *sock,unsigned char ip[4], int port, int type);
00100 static int init_server(int *sock, int port, int type);
00101 static int init_server_long(int *sock, int port,char *ip, int type);
00102 static int do_accept(int acc_sock, int *sock, char **host);
00103 static int host_ip(char *str, unsigned char ip[4]);
00104 
00105 #ifdef OPENSSL_SYS_WIN16
00106 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
00107 #else
00108 #define SOCKET_PROTOCOL IPPROTO_TCP
00109 #endif
00110 
00111 #if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
00112 static int wsa_init_done=0;
00113 #endif
00114 
00115 #ifdef OPENSSL_SYS_WINDOWS
00116 static struct WSAData wsa_state;
00117 static int wsa_init_done=0;
00118 
00119 #ifdef OPENSSL_SYS_WIN16
00120 static HWND topWnd=0;
00121 static FARPROC lpTopWndProc=NULL;
00122 static FARPROC lpTopHookProc=NULL;
00123 extern HINSTANCE _hInstance;  /* nice global CRT provides */
00124 
00125 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
00126              LPARAM lParam)
00127         {
00128         if (hwnd == topWnd)
00129                 {
00130                 switch(message)
00131                         {
00132                 case WM_DESTROY:
00133                 case WM_CLOSE:
00134                         SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
00135                         ssl_sock_cleanup();
00136                         break;
00137                         }
00138                 }
00139         return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
00140         }
00141 
00142 static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
00143         {
00144         topWnd=hwnd;
00145         return(FALSE);
00146         }
00147 
00148 #endif /* OPENSSL_SYS_WIN32 */
00149 #endif /* OPENSSL_SYS_WINDOWS */
00150 
00151 #ifdef OPENSSL_SYS_WINDOWS
00152 static void ssl_sock_cleanup(void)
00153         {
00154         if (wsa_init_done)
00155                 {
00156                 wsa_init_done=0;
00157 #ifndef OPENSSL_SYS_WINCE
00158                 WSACancelBlockingCall();
00159 #endif
00160                 WSACleanup();
00161                 }
00162         }
00163 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
00164 static void sock_cleanup(void)
00165     {
00166     if (wsa_init_done)
00167         {
00168         wsa_init_done=0;
00169                 WSACleanup();
00170                 }
00171         }
00172 #endif
00173 
00174 static int ssl_sock_init(void)
00175         {
00176 #ifdef WATT32
00177         extern int _watt_do_exit;
00178         _watt_do_exit = 0;
00179         if (sock_init())
00180                 return (0);
00181 #elif defined(OPENSSL_SYS_WINDOWS)
00182         if (!wsa_init_done)
00183                 {
00184                 int err;
00185           
00186 #ifdef SIGINT
00187                 signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
00188 #endif
00189                 wsa_init_done=1;
00190                 memset(&wsa_state,0,sizeof(wsa_state));
00191                 if (WSAStartup(0x0101,&wsa_state)!=0)
00192                         {
00193                         err=WSAGetLastError();
00194                         BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
00195                         return(0);
00196                         }
00197 
00198 #ifdef OPENSSL_SYS_WIN16
00199                 EnumTaskWindows(GetCurrentTask(),enumproc,0L);
00200                 lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
00201                 lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
00202 
00203                 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
00204 #endif /* OPENSSL_SYS_WIN16 */
00205                 }
00206 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
00207    WORD wVerReq;
00208    WSADATA wsaData;
00209    int err;
00210 
00211    if (!wsa_init_done)
00212       {
00213    
00214 # ifdef SIGINT
00215       signal(SIGINT,(void (*)(int))sock_cleanup);
00216 # endif
00217 
00218       wsa_init_done=1;
00219       wVerReq = MAKEWORD( 2, 0 );
00220       err = WSAStartup(wVerReq,&wsaData);
00221       if (err != 0)
00222          {
00223          BIO_printf(bio_err,"unable to start WINSOCK2, error code=%d\n",err);
00224          return(0);
00225          }
00226       }
00227 #endif /* OPENSSL_SYS_WINDOWS */
00228         return(1);
00229         }
00230 
00231 int init_client(int *sock, char *host, int port, int type)
00232         {
00233         unsigned char ip[4];
00234         short p=0;
00235 
00236         if (!host_ip(host,&(ip[0])))
00237                 {
00238                 return(0);
00239                 }
00240         if (p != 0) port=p;
00241         return(init_client_ip(sock,ip,port,type));
00242         }
00243 
00244 static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
00245         {
00246         unsigned long addr;
00247         struct sockaddr_in them;
00248         int s,i;
00249 
00250         if (!ssl_sock_init()) return(0);
00251 
00252         memset((char *)&them,0,sizeof(them));
00253         them.sin_family=AF_INET;
00254         them.sin_port=htons((unsigned short)port);
00255         addr=(unsigned long)
00256                 ((unsigned long)ip[0]<<24L)|
00257                 ((unsigned long)ip[1]<<16L)|
00258                 ((unsigned long)ip[2]<< 8L)|
00259                 ((unsigned long)ip[3]);
00260         them.sin_addr.s_addr=htonl(addr);
00261 
00262         if (type == SOCK_STREAM)
00263                 s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
00264         else /* ( type == SOCK_DGRAM) */
00265                 s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
00266                         
00267         if (s == INVALID_SOCKET) { perror("socket"); return(0); }
00268 
00269 #ifndef OPENSSL_SYS_MPE
00270         if (type == SOCK_STREAM)
00271                 {
00272                 i=0;
00273                 i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
00274                 if (i < 0) { perror("keepalive"); return(0); }
00275                 }
00276 #endif
00277 
00278         if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
00279                 { close(s); perror("connect"); return(0); }
00280         *sock=s;
00281         return(1);
00282         }
00283 
00284 int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), unsigned char *context)
00285         {
00286         int sock;
00287         char *name = NULL;
00288         int accept_socket;
00289         int i;
00290 
00291         if (!init_server(&accept_socket,port,type)) return(0);
00292 
00293         if (ret != NULL)
00294                 {
00295                 *ret=accept_socket;
00296                 /* return(1);*/
00297                 }
00298         for (;;)
00299                 {
00300                 if (type==SOCK_STREAM)
00301                         {
00302                         if (do_accept(accept_socket,&sock,&name) == 0)
00303                                 {
00304                                 SHUTDOWN(accept_socket);
00305                                 return(0);
00306                                 }
00307                         }
00308                 else
00309                         sock = accept_socket;
00310                 i=(*cb)(name,sock, context);
00311                 if (name != NULL) OPENSSL_free(name);
00312                 if (type==SOCK_STREAM)
00313                         SHUTDOWN2(sock);
00314                 if (i < 0)
00315                         {
00316                         SHUTDOWN2(accept_socket);
00317                         return(i);
00318                         }
00319                 }
00320         }
00321 
00322 static int init_server_long(int *sock, int port, char *ip, int type)
00323         {
00324         int ret=0;
00325         struct sockaddr_in server;
00326         int s= -1,i;
00327 
00328         if (!ssl_sock_init()) return(0);
00329 
00330         memset((char *)&server,0,sizeof(server));
00331         server.sin_family=AF_INET;
00332         server.sin_port=htons((unsigned short)port);
00333         if (ip == NULL)
00334                 server.sin_addr.s_addr=INADDR_ANY;
00335         else
00336 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
00337 #ifndef BIT_FIELD_LIMITS
00338                 memcpy(&server.sin_addr.s_addr,ip,4);
00339 #else
00340                 memcpy(&server.sin_addr,ip,4);
00341 #endif
00342         
00343                 if (type == SOCK_STREAM)
00344                         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
00345                 else /* type == SOCK_DGRAM */
00346                         s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
00347 
00348         if (s == INVALID_SOCKET) goto err;
00349 #if defined SOL_SOCKET && defined SO_REUSEADDR
00350                 {
00351                 int j = 1;
00352                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
00353                            (void *) &j, sizeof j);
00354                 }
00355 #endif
00356         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
00357                 {
00358 #ifndef OPENSSL_SYS_WINDOWS
00359                 perror("bind");
00360 #endif
00361                 goto err;
00362                 }
00363         /* Make it 128 for linux */
00364         if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
00365         i=0;
00366         *sock=s;
00367         ret=1;
00368 err:
00369         if ((ret == 0) && (s != -1))
00370                 {
00371                 SHUTDOWN(s);
00372                 }
00373         return(ret);
00374         }
00375 
00376 static int init_server(int *sock, int port, int type)
00377         {
00378         return(init_server_long(sock, port, NULL, type));
00379         }
00380 
00381 static int do_accept(int acc_sock, int *sock, char **host)
00382         {
00383         int ret,i;
00384         struct hostent *h1,*h2;
00385         static struct sockaddr_in from;
00386         int len;
00387 /*      struct linger ling; */
00388 
00389         if (!ssl_sock_init()) return(0);
00390 
00391 #ifndef OPENSSL_SYS_WINDOWS
00392 redoit:
00393 #endif
00394 
00395         memset((char *)&from,0,sizeof(from));
00396         len=sizeof(from);
00397         /* Note: under VMS with SOCKETSHR the fourth parameter is currently
00398          * of type (int *) whereas under other systems it is (void *) if
00399          * you don't have a cast it will choke the compiler: if you do
00400          * have a cast then you can either go for (int *) or (void *).
00401          */
00402         ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
00403         if (ret == INVALID_SOCKET)
00404                 {
00405 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
00406                 i=WSAGetLastError();
00407                 BIO_printf(bio_err,"accept error %d\n",i);
00408 #else
00409                 if (errno == EINTR)
00410                         {
00411                         /*check_timeout(); */
00412                         goto redoit;
00413                         }
00414                 fprintf(stderr,"errno=%d ",errno);
00415                 perror("accept");
00416 #endif
00417                 return(0);
00418                 }
00419 
00420 /*
00421         ling.l_onoff=1;
00422         ling.l_linger=0;
00423         i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
00424         if (i < 0) { perror("linger"); return(0); }
00425         i=0;
00426         i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
00427         if (i < 0) { perror("keepalive"); return(0); }
00428 */
00429 
00430         if (host == NULL) goto end;
00431 #ifndef BIT_FIELD_LIMITS
00432         /* I should use WSAAsyncGetHostByName() under windows */
00433         h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
00434                 sizeof(from.sin_addr.s_addr),AF_INET);
00435 #else
00436         h1=gethostbyaddr((char *)&from.sin_addr,
00437                 sizeof(struct in_addr),AF_INET);
00438 #endif
00439         if (h1 == NULL)
00440                 {
00441                 BIO_printf(bio_err,"bad gethostbyaddr\n");
00442                 *host=NULL;
00443                 /* return(0); */
00444                 }
00445         else
00446                 {
00447                 if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
00448                         {
00449                         perror("OPENSSL_malloc");
00450                         return(0);
00451                         }
00452                 BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
00453 
00454                 h2=GetHostByName(*host);
00455                 if (h2 == NULL)
00456                         {
00457                         BIO_printf(bio_err,"gethostbyname failure\n");
00458                         return(0);
00459                         }
00460                 i=0;
00461                 if (h2->h_addrtype != AF_INET)
00462                         {
00463                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
00464                         return(0);
00465                         }
00466                 }
00467 end:
00468         *sock=ret;
00469         return(1);
00470         }
00471 
00472 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
00473              short *port_ptr)
00474         {
00475         char *h,*p;
00476 
00477         h=str;
00478         p=strchr(str,':');
00479         if (p == NULL)
00480                 {
00481                 BIO_printf(bio_err,"no port defined\n");
00482                 return(0);
00483                 }
00484         *(p++)='\0';
00485 
00486         if ((ip != NULL) && !host_ip(str,ip))
00487                 goto err;
00488         if (host_ptr != NULL) *host_ptr=h;
00489 
00490         if (!extract_port(p,port_ptr))
00491                 goto err;
00492         return(1);
00493 err:
00494         return(0);
00495         }
00496 
00497 static int host_ip(char *str, unsigned char ip[4])
00498         {
00499         unsigned int in[4]; 
00500         int i;
00501 
00502         if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
00503                 {
00504                 for (i=0; i<4; i++)
00505                         if (in[i] > 255)
00506                                 {
00507                                 BIO_printf(bio_err,"invalid IP address\n");
00508                                 goto err;
00509                                 }
00510                 ip[0]=in[0];
00511                 ip[1]=in[1];
00512                 ip[2]=in[2];
00513                 ip[3]=in[3];
00514                 }
00515         else
00516                 { /* do a gethostbyname */
00517                 struct hostent *he;
00518 
00519                 if (!ssl_sock_init()) return(0);
00520 
00521                 he=GetHostByName(str);
00522                 if (he == NULL)
00523                         {
00524                         BIO_printf(bio_err,"gethostbyname failure\n");
00525                         goto err;
00526                         }
00527                 /* cast to short because of win16 winsock definition */
00528                 if ((short)he->h_addrtype != AF_INET)
00529                         {
00530                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
00531                         return(0);
00532                         }
00533                 ip[0]=he->h_addr_list[0][0];
00534                 ip[1]=he->h_addr_list[0][1];
00535                 ip[2]=he->h_addr_list[0][2];
00536                 ip[3]=he->h_addr_list[0][3];
00537                 }
00538         return(1);
00539 err:
00540         return(0);
00541         }
00542 
00543 int extract_port(char *str, short *port_ptr)
00544         {
00545         int i;
00546         struct servent *s;
00547 
00548         i=atoi(str);
00549         if (i != 0)
00550                 *port_ptr=(unsigned short)i;
00551         else
00552                 {
00553                 s=getservbyname(str,"tcp");
00554                 if (s == NULL)
00555                         {
00556                         BIO_printf(bio_err,"getservbyname failure for %s\n",str);
00557                         return(0);
00558                         }
00559                 *port_ptr=ntohs((unsigned short)s->s_port);
00560                 }
00561         return(1);
00562         }
00563 
00564 #define GHBN_NUM        4
00565 static struct ghbn_cache_st
00566         {
00567         char name[128];
00568         struct hostent ent;
00569         unsigned long order;
00570         } ghbn_cache[GHBN_NUM];
00571 
00572 static unsigned long ghbn_hits=0L;
00573 static unsigned long ghbn_miss=0L;
00574 
00575 static struct hostent *GetHostByName(char *name)
00576         {
00577         struct hostent *ret;
00578         int i,lowi=0;
00579         unsigned long low= (unsigned long)-1;
00580 
00581         for (i=0; i<GHBN_NUM; i++)
00582                 {
00583                 if (low > ghbn_cache[i].order)
00584                         {
00585                         low=ghbn_cache[i].order;
00586                         lowi=i;
00587                         }
00588                 if (ghbn_cache[i].order > 0)
00589                         {
00590                         if (strncmp(name,ghbn_cache[i].name,128) == 0)
00591                                 break;
00592                         }
00593                 }
00594         if (i == GHBN_NUM) /* no hit*/
00595                 {
00596                 ghbn_miss++;
00597                 ret=gethostbyname(name);
00598                 if (ret == NULL) return(NULL);
00599                 /* else add to cache */
00600                 if(strlen(name) < sizeof ghbn_cache[0].name)
00601                         {
00602                         strcpy(ghbn_cache[lowi].name,name);
00603                         memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
00604                         ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
00605                         }
00606                 return(ret);
00607                 }
00608         else
00609                 {
00610                 ghbn_hits++;
00611                 ret= &(ghbn_cache[i].ent);
00612                 ghbn_cache[i].order=ghbn_miss+ghbn_hits;
00613                 return(ret);
00614                 }
00615         }
00616 
00617 #endif

© sourcejam.com 2005-2008