added files
[bcm963xx.git] / userapps / opensource / openssl / 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 #ifndef OPENSSL_SYS_WINCE
144                 WSACancelBlockingCall();
145 #endif
146                 WSACleanup();
147                 }
148         }
149 #endif
150
151 static int ssl_sock_init(void)
152         {
153 #ifdef WATT32
154         extern int _watt_do_exit;
155         _watt_do_exit = 0;
156         if (sock_init())
157                 return (0);
158 #elif defined(OPENSSL_SYS_WINDOWS)
159         if (!wsa_init_done)
160                 {
161                 int err;
162           
163 #ifdef SIGINT
164                 signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
165 #endif
166                 wsa_init_done=1;
167                 memset(&wsa_state,0,sizeof(wsa_state));
168                 if (WSAStartup(0x0101,&wsa_state)!=0)
169                         {
170                         err=WSAGetLastError();
171                         BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
172                         return(0);
173                         }
174
175 #ifdef OPENSSL_SYS_WIN16
176                 EnumTaskWindows(GetCurrentTask(),enumproc,0L);
177                 lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
178                 lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
179
180                 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
181 #endif /* OPENSSL_SYS_WIN16 */
182                 }
183 #endif /* OPENSSL_SYS_WINDOWS */
184         return(1);
185         }
186
187 int init_client(int *sock, char *host, int port)
188         {
189         unsigned char ip[4];
190         short p=0;
191
192         if (!host_ip(host,&(ip[0])))
193                 {
194                 return(0);
195                 }
196         if (p != 0) port=p;
197         return(init_client_ip(sock,ip,port));
198         }
199
200 static int init_client_ip(int *sock, unsigned char ip[4], int port)
201         {
202         unsigned long addr;
203         struct sockaddr_in them;
204         int s,i;
205
206         if (!ssl_sock_init()) return(0);
207
208         memset((char *)&them,0,sizeof(them));
209         them.sin_family=AF_INET;
210         them.sin_port=htons((unsigned short)port);
211         addr=(unsigned long)
212                 ((unsigned long)ip[0]<<24L)|
213                 ((unsigned long)ip[1]<<16L)|
214                 ((unsigned long)ip[2]<< 8L)|
215                 ((unsigned long)ip[3]);
216         them.sin_addr.s_addr=htonl(addr);
217
218         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
219         if (s == INVALID_SOCKET) { perror("socket"); return(0); }
220
221 #ifndef OPENSSL_SYS_MPE
222         i=0;
223         i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
224         if (i < 0) { perror("keepalive"); return(0); }
225 #endif
226
227         if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
228                 { close(s); perror("connect"); return(0); }
229         *sock=s;
230         return(1);
231         }
232
233 int do_server(int port, int *ret, int (*cb)(), char *context)
234         {
235         int sock;
236         char *name;
237         int accept_socket;
238         int i;
239
240         if (!init_server(&accept_socket,port)) return(0);
241
242         if (ret != NULL)
243                 {
244                 *ret=accept_socket;
245                 /* return(1);*/
246                 }
247         for (;;)
248                 {
249                 if (do_accept(accept_socket,&sock,&name) == 0)
250                         {
251                         SHUTDOWN(accept_socket);
252                         return(0);
253                         }
254                 i=(*cb)(name,sock, context);
255                 if (name != NULL) OPENSSL_free(name);
256                 SHUTDOWN2(sock);
257                 if (i < 0)
258                         {
259                         SHUTDOWN2(accept_socket);
260                         return(i);
261                         }
262                 }
263         }
264
265 static int init_server_long(int *sock, int port, char *ip)
266         {
267         int ret=0;
268         struct sockaddr_in server;
269         int s= -1,i;
270
271         if (!ssl_sock_init()) return(0);
272
273         memset((char *)&server,0,sizeof(server));
274         server.sin_family=AF_INET;
275         server.sin_port=htons((unsigned short)port);
276         if (ip == NULL)
277                 server.sin_addr.s_addr=INADDR_ANY;
278         else
279 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
280 #ifndef BIT_FIELD_LIMITS
281                 memcpy(&server.sin_addr.s_addr,ip,4);
282 #else
283                 memcpy(&server.sin_addr,ip,4);
284 #endif
285         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
286
287         if (s == INVALID_SOCKET) goto err;
288 #if defined SOL_SOCKET && defined SO_REUSEADDR
289                 {
290                 int j = 1;
291                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
292                            (void *) &j, sizeof j);
293                 }
294 #endif
295         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
296                 {
297 #ifndef OPENSSL_SYS_WINDOWS
298                 perror("bind");
299 #endif
300                 goto err;
301                 }
302         /* Make it 128 for linux */
303         if (listen(s,128) == -1) goto err;
304         i=0;
305         *sock=s;
306         ret=1;
307 err:
308         if ((ret == 0) && (s != -1))
309                 {
310                 SHUTDOWN(s);
311                 }
312         return(ret);
313         }
314
315 static int init_server(int *sock, int port)
316         {
317         return(init_server_long(sock, port, NULL));
318         }
319
320 static int do_accept(int acc_sock, int *sock, char **host)
321         {
322         int ret,i;
323         struct hostent *h1,*h2;
324         static struct sockaddr_in from;
325         int len;
326 /*      struct linger ling; */
327
328         if (!ssl_sock_init()) return(0);
329
330 #ifndef OPENSSL_SYS_WINDOWS
331 redoit:
332 #endif
333
334         memset((char *)&from,0,sizeof(from));
335         len=sizeof(from);
336         /* Note: under VMS with SOCKETSHR the fourth parameter is currently
337          * of type (int *) whereas under other systems it is (void *) if
338          * you don't have a cast it will choke the compiler: if you do
339          * have a cast then you can either go for (int *) or (void *).
340          */
341         ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
342         if (ret == INVALID_SOCKET)
343                 {
344 #ifdef OPENSSL_SYS_WINDOWS
345                 i=WSAGetLastError();
346                 BIO_printf(bio_err,"accept error %d\n",i);
347 #else
348                 if (errno == EINTR)
349                         {
350                         /*check_timeout(); */
351                         goto redoit;
352                         }
353                 fprintf(stderr,"errno=%d ",errno);
354                 perror("accept");
355 #endif
356                 return(0);
357                 }
358
359 /*
360         ling.l_onoff=1;
361         ling.l_linger=0;
362         i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
363         if (i < 0) { perror("linger"); return(0); }
364         i=0;
365         i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
366         if (i < 0) { perror("keepalive"); return(0); }
367 */
368
369         if (host == NULL) goto end;
370 #ifndef BIT_FIELD_LIMITS
371         /* I should use WSAAsyncGetHostByName() under windows */
372         h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
373                 sizeof(from.sin_addr.s_addr),AF_INET);
374 #else
375         h1=gethostbyaddr((char *)&from.sin_addr,
376                 sizeof(struct in_addr),AF_INET);
377 #endif
378         if (h1 == NULL)
379                 {
380                 BIO_printf(bio_err,"bad gethostbyaddr\n");
381                 *host=NULL;
382                 /* return(0); */
383                 }
384         else
385                 {
386                 if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
387                         {
388                         perror("OPENSSL_malloc");
389                         return(0);
390                         }
391                 BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
392
393                 h2=GetHostByName(*host);
394                 if (h2 == NULL)
395                         {
396                         BIO_printf(bio_err,"gethostbyname failure\n");
397                         return(0);
398                         }
399                 i=0;
400                 if (h2->h_addrtype != AF_INET)
401                         {
402                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
403                         return(0);
404                         }
405                 }
406 end:
407         *sock=ret;
408         return(1);
409         }
410
411 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
412              short *port_ptr)
413         {
414         char *h,*p;
415
416         h=str;
417         p=strchr(str,':');
418         if (p == NULL)
419                 {
420                 BIO_printf(bio_err,"no port defined\n");
421                 return(0);
422                 }
423         *(p++)='\0';
424
425         if ((ip != NULL) && !host_ip(str,ip))
426                 goto err;
427         if (host_ptr != NULL) *host_ptr=h;
428
429         if (!extract_port(p,port_ptr))
430                 goto err;
431         return(1);
432 err:
433         return(0);
434         }
435
436 static int host_ip(char *str, unsigned char ip[4])
437         {
438         unsigned int in[4]; 
439         int i;
440
441         if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
442                 {
443                 for (i=0; i<4; i++)
444                         if (in[i] > 255)
445                                 {
446                                 BIO_printf(bio_err,"invalid IP address\n");
447                                 goto err;
448                                 }
449                 ip[0]=in[0];
450                 ip[1]=in[1];
451                 ip[2]=in[2];
452                 ip[3]=in[3];
453                 }
454         else
455                 { /* do a gethostbyname */
456                 struct hostent *he;
457
458                 if (!ssl_sock_init()) return(0);
459
460                 he=GetHostByName(str);
461                 if (he == NULL)
462                         {
463                         BIO_printf(bio_err,"gethostbyname failure\n");
464                         goto err;
465                         }
466                 /* cast to short because of win16 winsock definition */
467                 if ((short)he->h_addrtype != AF_INET)
468                         {
469                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
470                         return(0);
471                         }
472                 ip[0]=he->h_addr_list[0][0];
473                 ip[1]=he->h_addr_list[0][1];
474                 ip[2]=he->h_addr_list[0][2];
475                 ip[3]=he->h_addr_list[0][3];
476                 }
477         return(1);
478 err:
479         return(0);
480         }
481
482 int extract_port(char *str, short *port_ptr)
483         {
484         int i;
485         struct servent *s;
486
487         i=atoi(str);
488         if (i != 0)
489                 *port_ptr=(unsigned short)i;
490         else
491                 {
492                 s=getservbyname(str,"tcp");
493                 if (s == NULL)
494                         {
495                         BIO_printf(bio_err,"getservbyname failure for %s\n",str);
496                         return(0);
497                         }
498                 *port_ptr=ntohs((unsigned short)s->s_port);
499                 }
500         return(1);
501         }
502
503 #define GHBN_NUM        4
504 static struct ghbn_cache_st
505         {
506         char name[128];
507         struct hostent ent;
508         unsigned long order;
509         } ghbn_cache[GHBN_NUM];
510
511 static unsigned long ghbn_hits=0L;
512 static unsigned long ghbn_miss=0L;
513
514 static struct hostent *GetHostByName(char *name)
515         {
516         struct hostent *ret;
517         int i,lowi=0;
518         unsigned long low= (unsigned long)-1;
519
520         for (i=0; i<GHBN_NUM; i++)
521                 {
522                 if (low > ghbn_cache[i].order)
523                         {
524                         low=ghbn_cache[i].order;
525                         lowi=i;
526                         }
527                 if (ghbn_cache[i].order > 0)
528                         {
529                         if (strncmp(name,ghbn_cache[i].name,128) == 0)
530                                 break;
531                         }
532                 }
533         if (i == GHBN_NUM) /* no hit*/
534                 {
535                 ghbn_miss++;
536                 ret=gethostbyname(name);
537                 if (ret == NULL) return(NULL);
538                 /* else add to cache */
539                 if(strlen(name) < sizeof ghbn_cache[0].name)
540                         {
541                         strcpy(ghbn_cache[lowi].name,name);
542                         memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
543                         ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
544                         }
545                 return(ret);
546                 }
547         else
548                 {
549                 ghbn_hits++;
550                 ret= &(ghbn_cache[i].ent);
551                 ghbn_cache[i].order=ghbn_miss+ghbn_hits;
552                 return(ret);
553                 }
554         }