source: trunk/third/openssl/apps/s_socket.c @ 18442

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