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

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