ed15ce0c1ddcb3867032a8bbfda4b710cb669e2a
[openssl.git] / apps / s_socket.c
1 /* apps/s_socket.c -  socket-related functions used by s_client and s_server */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <errno.h>
63 #include <signal.h>
64
65 #include <openssl/e_os2.h>
66
67 /* With IPv6, it looks like Digital has mixed up the proper order of
68    recursive header file inclusion, resulting in the compiler complaining
69    that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
70    is needed to have fileno() declared correctly...  So let's define u_int */
71 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
72 #define __U_INT
73 typedef unsigned int u_int;
74 #endif
75
76 #define USE_SOCKETS
77 #define NON_MAIN
78 #include "apps.h"
79 #undef USE_SOCKETS
80 #undef NON_MAIN
81 #include "s_apps.h"
82 #include <openssl/ssl.h>
83
84 static struct hostent *GetHostByName(char *name);
85 #ifdef OPENSSL_SYS_WINDOWS
86 static void ssl_sock_cleanup(void);
87 #endif
88 static int ssl_sock_init(void);
89 static int init_client_ip(int *sock,unsigned char ip[4], int port);
90 static int init_server(int *sock, int port);
91 static int init_server_long(int *sock, int port,char *ip);
92 static int do_accept(int acc_sock, int *sock, char **host);
93 static int host_ip(char *str, unsigned char ip[4]);
94
95 #ifdef OPENSSL_SYS_WIN16
96 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
97 #else
98 #define SOCKET_PROTOCOL IPPROTO_TCP
99 #endif
100
101 #ifdef OPENSSL_SYS_WINDOWS
102 static struct WSAData wsa_state;
103 static int wsa_init_done=0;
104
105 #ifdef OPENSSL_SYS_WIN16
106 static HWND topWnd=0;
107 static FARPROC lpTopWndProc=NULL;
108 static FARPROC lpTopHookProc=NULL;
109 extern HINSTANCE _hInstance;  /* nice global CRT provides */
110
111 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
112              LPARAM lParam)
113         {
114         if (hwnd == topWnd)
115                 {
116                 switch(message)
117                         {
118                 case WM_DESTROY:
119                 case WM_CLOSE:
120                         SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
121                         ssl_sock_cleanup();
122                         break;
123                         }
124                 }
125         return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
126         }
127
128 static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
129         {
130         topWnd=hwnd;
131         return(FALSE);
132         }
133
134 #endif /* OPENSSL_SYS_WIN32 */
135 #endif /* OPENSSL_SYS_WINDOWS */
136
137 #ifdef OPENSSL_SYS_WINDOWS
138 static void ssl_sock_cleanup(void)
139         {
140         if (wsa_init_done)
141                 {
142                 wsa_init_done=0;
143                 WSACancelBlockingCall();
144                 WSACleanup();
145                 }
146         }
147 #endif
148
149 static int ssl_sock_init(void)
150         {
151 #ifdef WATT32
152         extern int _watt_do_exit;
153         _watt_do_exit = 0;
154         dbug_init();
155         if (sock_init())
156                 return (0);
157 #elif defined(OPENSSL_SYS_WINDOWS)
158         if (!wsa_init_done)
159                 {
160                 int err;
161           
162 #ifdef SIGINT
163                 signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
164 #endif
165                 wsa_init_done=1;
166                 memset(&wsa_state,0,sizeof(wsa_state));
167                 if (WSAStartup(0x0101,&wsa_state)!=0)
168                         {
169                         err=WSAGetLastError();
170                         BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
171                         return(0);
172                         }
173
174 #ifdef OPENSSL_SYS_WIN16
175                 EnumTaskWindows(GetCurrentTask(),enumproc,0L);
176                 lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
177                 lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
178
179                 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
180 #endif /* OPENSSL_SYS_WIN16 */
181                 }
182 #endif /* OPENSSL_SYS_WINDOWS */
183         return(1);
184         }
185
186 int init_client(int *sock, char *host, int port)
187         {
188         unsigned char ip[4];
189         short p=0;
190
191         if (!host_ip(host,&(ip[0])))
192                 {
193                 return(0);
194                 }
195         if (p != 0) port=p;
196         return(init_client_ip(sock,ip,port));
197         }
198
199 static int init_client_ip(int *sock, unsigned char ip[4], int port)
200         {
201         unsigned long addr;
202         struct sockaddr_in them;
203         int s,i;
204
205         if (!ssl_sock_init()) return(0);
206
207         memset((char *)&them,0,sizeof(them));
208         them.sin_family=AF_INET;
209         them.sin_port=htons((unsigned short)port);
210         addr=(unsigned long)
211                 ((unsigned long)ip[0]<<24L)|
212                 ((unsigned long)ip[1]<<16L)|
213                 ((unsigned long)ip[2]<< 8L)|
214                 ((unsigned long)ip[3]);
215         them.sin_addr.s_addr=htonl(addr);
216
217         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
218         if (s == INVALID_SOCKET) { perror("socket"); return(0); }
219
220 #ifndef OPENSSL_SYS_MPE
221         i=0;
222         i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
223         if (i < 0) { perror("keepalive"); return(0); }
224 #endif
225
226         if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
227                 { close(s); perror("connect"); return(0); }
228         *sock=s;
229         return(1);
230         }
231
232 int do_server(int port, int *ret, int (*cb)(), char *context)
233         {
234         int sock;
235         char *name;
236         int accept_socket;
237         int i;
238
239         if (!init_server(&accept_socket,port)) return(0);
240
241         if (ret != NULL)
242                 {
243                 *ret=accept_socket;
244                 /* return(1);*/
245                 }
246         for (;;)
247                 {
248                 if (do_accept(accept_socket,&sock,&name) == 0)
249                         {
250                         SHUTDOWN(accept_socket);
251                         return(0);
252                         }
253                 i=(*cb)(name,sock, context);
254                 if (name != NULL) OPENSSL_free(name);
255                 SHUTDOWN2(sock);
256                 if (i < 0)
257                         {
258                         SHUTDOWN2(accept_socket);
259                         return(i);
260                         }
261                 }
262         }
263
264 static int init_server_long(int *sock, int port, char *ip)
265         {
266         int ret=0;
267         struct sockaddr_in server;
268         int s= -1,i;
269
270         if (!ssl_sock_init()) return(0);
271
272         memset((char *)&server,0,sizeof(server));
273         server.sin_family=AF_INET;
274         server.sin_port=htons((unsigned short)port);
275         if (ip == NULL)
276                 server.sin_addr.s_addr=INADDR_ANY;
277         else
278 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
279 #ifndef BIT_FIELD_LIMITS
280                 memcpy(&server.sin_addr.s_addr,ip,4);
281 #else
282                 memcpy(&server.sin_addr,ip,4);
283 #endif
284         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
285
286         if (s == INVALID_SOCKET) goto err;
287 #if defined SOL_SOCKET && defined SO_REUSEADDR
288                 {
289                 int j = 1;
290                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
291                            (void *) &j, sizeof j);
292                 }
293 #endif
294         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
295                 {
296 #ifndef OPENSSL_SYS_WINDOWS
297                 perror("bind");
298 #endif
299                 goto err;
300                 }
301         /* Make it 128 for linux */
302         if (listen(s,128) == -1) goto err;
303         i=0;
304         *sock=s;
305         ret=1;
306 err:
307         if ((ret == 0) && (s != -1))
308                 {
309                 SHUTDOWN(s);
310                 }
311         return(ret);
312         }
313
314 static int init_server(int *sock, int port)
315         {
316         return(init_server_long(sock, port, NULL));
317         }
318
319 static int do_accept(int acc_sock, int *sock, char **host)
320         {
321         int ret,i;
322         struct hostent *h1,*h2;
323         static struct sockaddr_in from;
324         int len;
325 /*      struct linger ling; */
326
327         if (!ssl_sock_init()) return(0);
328
329 #ifndef OPENSSL_SYS_WINDOWS
330 redoit:
331 #endif
332
333         memset((char *)&from,0,sizeof(from));
334         len=sizeof(from);
335         /* Note: under VMS with SOCKETSHR the fourth parameter is currently
336          * of type (int *) whereas under other systems it is (void *) if
337          * you don't have a cast it will choke the compiler: if you do
338          * have a cast then you can either go for (int *) or (void *).
339          */
340         ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
341         if (ret == INVALID_SOCKET)
342                 {
343 #ifdef OPENSSL_SYS_WINDOWS
344                 i=WSAGetLastError();
345                 BIO_printf(bio_err,"accept error %d\n",i);
346 #else
347                 if (errno == EINTR)
348                         {
349                         /*check_timeout(); */
350                         goto redoit;
351                         }
352                 fprintf(stderr,"errno=%d ",errno);
353                 perror("accept");
354 #endif
355                 return(0);
356                 }
357
358 /*
359         ling.l_onoff=1;
360         ling.l_linger=0;
361         i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
362         if (i < 0) { perror("linger"); return(0); }
363         i=0;
364         i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
365         if (i < 0) { perror("keepalive"); return(0); }
366 */
367
368         if (host == NULL) goto end;
369 #ifndef BIT_FIELD_LIMITS
370         /* I should use WSAAsyncGetHostByName() under windows */
371         h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
372                 sizeof(from.sin_addr.s_addr),AF_INET);
373 #else
374         h1=gethostbyaddr((char *)&from.sin_addr,
375                 sizeof(struct in_addr),AF_INET);
376 #endif
377         if (h1 == NULL)
378                 {
379                 BIO_printf(bio_err,"bad gethostbyaddr\n");
380                 *host=NULL;
381                 /* return(0); */
382                 }
383         else
384                 {
385                 if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
386                         {
387                         perror("OPENSSL_malloc");
388                         return(0);
389                         }
390                 strcpy(*host,h1->h_name);
391
392                 h2=GetHostByName(*host);
393                 if (h2 == NULL)
394                         {
395                         BIO_printf(bio_err,"gethostbyname failure\n");
396                         return(0);
397                         }
398                 i=0;
399                 if (h2->h_addrtype != AF_INET)
400                         {
401                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
402                         return(0);
403                         }
404                 }
405 end:
406         *sock=ret;
407         return(1);
408         }
409
410 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
411              short *port_ptr)
412         {
413         char *h,*p;
414
415         h=str;
416         p=strchr(str,':');
417         if (p == NULL)
418                 {
419                 BIO_printf(bio_err,"no port defined\n");
420                 return(0);
421                 }
422         *(p++)='\0';
423
424         if ((ip != NULL) && !host_ip(str,ip))
425                 goto err;
426         if (host_ptr != NULL) *host_ptr=h;
427
428         if (!extract_port(p,port_ptr))
429                 goto err;
430         return(1);
431 err:
432         return(0);
433         }
434
435 static int host_ip(char *str, unsigned char ip[4])
436         {
437         unsigned int in[4]; 
438         int i;
439
440         if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
441                 {
442                 for (i=0; i<4; i++)
443                         if (in[i] > 255)
444                                 {
445                                 BIO_printf(bio_err,"invalid IP address\n");
446                                 goto err;
447                                 }
448                 ip[0]=in[0];
449                 ip[1]=in[1];
450                 ip[2]=in[2];
451                 ip[3]=in[3];
452                 }
453         else
454                 { /* do a gethostbyname */
455                 struct hostent *he;
456
457                 if (!ssl_sock_init()) return(0);
458
459                 he=GetHostByName(str);
460                 if (he == NULL)
461                         {
462                         BIO_printf(bio_err,"gethostbyname failure\n");
463                         goto err;
464                         }
465                 /* cast to short because of win16 winsock definition */
466                 if ((short)he->h_addrtype != AF_INET)
467                         {
468                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
469                         return(0);
470                         }
471                 ip[0]=he->h_addr_list[0][0];
472                 ip[1]=he->h_addr_list[0][1];
473                 ip[2]=he->h_addr_list[0][2];
474                 ip[3]=he->h_addr_list[0][3];
475                 }
476         return(1);
477 err:
478         return(0);
479         }
480
481 int extract_port(char *str, short *port_ptr)
482         {
483         int i;
484         struct servent *s;
485
486         i=atoi(str);
487         if (i != 0)
488                 *port_ptr=(unsigned short)i;
489         else
490                 {
491                 s=getservbyname(str,"tcp");
492                 if (s == NULL)
493                         {
494                         BIO_printf(bio_err,"getservbyname failure for %s\n",str);
495                         return(0);
496                         }
497                 *port_ptr=ntohs((unsigned short)s->s_port);
498                 }
499         return(1);
500         }
501
502 #define GHBN_NUM        4
503 static struct ghbn_cache_st
504         {
505         char name[128];
506         struct hostent ent;
507         unsigned long order;
508         } ghbn_cache[GHBN_NUM];
509
510 static unsigned long ghbn_hits=0L;
511 static unsigned long ghbn_miss=0L;
512
513 static struct hostent *GetHostByName(char *name)
514         {
515         struct hostent *ret;
516         int i,lowi=0;
517         unsigned long low= (unsigned long)-1;
518
519         for (i=0; i<GHBN_NUM; i++)
520                 {
521                 if (low > ghbn_cache[i].order)
522                         {
523                         low=ghbn_cache[i].order;
524                         lowi=i;
525                         }
526                 if (ghbn_cache[i].order > 0)
527                         {
528                         if (strncmp(name,ghbn_cache[i].name,128) == 0)
529                                 break;
530                         }
531                 }
532         if (i == GHBN_NUM) /* no hit*/
533                 {
534                 ghbn_miss++;
535                 ret=gethostbyname(name);
536                 if (ret == NULL) return(NULL);
537                 /* else add to cache */
538                 if(strlen(name) < sizeof ghbn_cache[0].name)
539                         {
540                         strcpy(ghbn_cache[lowi].name,name);
541                         memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
542                         ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
543                         }
544                 return(ret);
545                 }
546         else
547                 {
548                 ghbn_hits++;
549                 ret= &(ghbn_cache[i].ent);
550                 ghbn_cache[i].order=ghbn_miss+ghbn_hits;
551                 return(ret);
552                 }
553         }