s_socket.c revision 55714
1/* apps/s_socket.c */
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
82#ifdef VMS
83#if (__VMS_VER < 70000000) /* FIONBIO used as a switch to enable ioctl,
84			      and that isn't in VMS < 7.0 */
85#undef FIONBIO
86#endif
87#include <processes.h> /* for vfork() */
88#endif
89
90static struct hostent *GetHostByName(char *name);
91int sock_init(void );
92#ifdef WIN16
93#define SOCKET_PROTOCOL	0 /* more microsoft stupidity */
94#else
95#define SOCKET_PROTOCOL	IPPROTO_TCP
96#endif
97
98#ifdef WINDOWS
99static struct WSAData wsa_state;
100static int wsa_init_done=0;
101
102#ifdef WIN16
103static HWND topWnd=0;
104static FARPROC lpTopWndProc=NULL;
105static FARPROC lpTopHookProc=NULL;
106extern HINSTANCE _hInstance;  /* nice global CRT provides */
107
108static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
109	     LPARAM lParam)
110	{
111	if (hwnd == topWnd)
112		{
113		switch(message)
114			{
115		case WM_DESTROY:
116		case WM_CLOSE:
117			SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
118			sock_cleanup();
119			break;
120			}
121		}
122	return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
123	}
124
125static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
126	{
127	topWnd=hwnd;
128	return(FALSE);
129	}
130
131#endif /* WIN32 */
132#endif /* WINDOWS */
133
134void sock_cleanup(void)
135	{
136#ifdef WINDOWS
137	if (wsa_init_done)
138		{
139		wsa_init_done=0;
140		WSACancelBlockingCall();
141		WSACleanup();
142		}
143#endif
144	}
145
146int sock_init(void)
147	{
148#ifdef WINDOWS
149	if (!wsa_init_done)
150		{
151		int err;
152
153#ifdef SIGINT
154		signal(SIGINT,(void (*)(int))sock_cleanup);
155#endif
156		wsa_init_done=1;
157		memset(&wsa_state,0,sizeof(wsa_state));
158		if (WSAStartup(0x0101,&wsa_state)!=0)
159			{
160			err=WSAGetLastError();
161			BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
162			return(0);
163			}
164
165#ifdef WIN16
166		EnumTaskWindows(GetCurrentTask(),enumproc,0L);
167		lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
168		lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
169
170		SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
171#endif /* WIN16 */
172		}
173#endif /* WINDOWS */
174	return(1);
175	}
176
177int init_client(int *sock, char *host, int port)
178	{
179	unsigned char ip[4];
180	short p=0;
181
182	if (!host_ip(host,&(ip[0])))
183		{
184		return(0);
185		}
186	if (p != 0) port=p;
187	return(init_client_ip(sock,ip,port));
188	}
189
190int init_client_ip(int *sock, unsigned char ip[4], int port)
191	{
192	unsigned long addr;
193	struct sockaddr_in them;
194	int s,i;
195
196	if (!sock_init()) return(0);
197
198	memset((char *)&them,0,sizeof(them));
199	them.sin_family=AF_INET;
200	them.sin_port=htons((unsigned short)port);
201	addr=(unsigned long)
202		((unsigned long)ip[0]<<24L)|
203		((unsigned long)ip[1]<<16L)|
204		((unsigned long)ip[2]<< 8L)|
205		((unsigned long)ip[3]);
206	them.sin_addr.s_addr=htonl(addr);
207
208	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
209	if (s == INVALID_SOCKET) { perror("socket"); return(0); }
210
211	i=0;
212	i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
213	if (i < 0) { perror("keepalive"); return(0); }
214
215	if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
216		{ close(s); perror("connect"); return(0); }
217	*sock=s;
218	return(1);
219	}
220
221int nbio_sock_error(int sock)
222	{
223	int j,i;
224	int size;
225
226	size=sizeof(int);
227	/* Note: under VMS with SOCKETSHR the third parameter is currently
228	 * of type (int *) whereas under other systems it is (void *) if
229	 * you don't have a cast it will choke the compiler: if you do
230	 * have a cast then you can either go for (int *) or (void *).
231	 */
232	i=getsockopt(sock,SOL_SOCKET,SO_ERROR,(char *)&j,(void *)&size);
233	if (i < 0)
234		return(1);
235	else
236		return(j);
237	}
238
239int nbio_init_client_ip(int *sock, unsigned char ip[4], int port)
240	{
241	unsigned long addr;
242	struct sockaddr_in them;
243	int s,i;
244
245	if (!sock_init()) return(0);
246
247	memset((char *)&them,0,sizeof(them));
248	them.sin_family=AF_INET;
249	them.sin_port=htons((unsigned short)port);
250	addr=	(unsigned long)
251		((unsigned long)ip[0]<<24L)|
252		((unsigned long)ip[1]<<16L)|
253		((unsigned long)ip[2]<< 8L)|
254		((unsigned long)ip[3]);
255	them.sin_addr.s_addr=htonl(addr);
256
257	if (*sock <= 0)
258		{
259#ifdef FIONBIO
260		unsigned long l=1;
261#endif
262
263		s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
264		if (s == INVALID_SOCKET) { perror("socket"); return(0); }
265
266		i=0;
267		i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
268		if (i < 0) { perror("keepalive"); return(0); }
269		*sock=s;
270
271#ifdef FIONBIO
272		BIO_socket_ioctl(s,FIONBIO,&l);
273#endif
274		}
275	else
276		s= *sock;
277
278	i=connect(s,(struct sockaddr *)&them,sizeof(them));
279	if (i == INVALID_SOCKET)
280		{
281		if (BIO_sock_should_retry(i))
282			return(-1);
283		else
284			return(0);
285		}
286	else
287		return(1);
288	}
289
290int do_server(int port, int *ret, int (*cb)(), char *context)
291	{
292	int sock;
293	char *name;
294	int accept_socket;
295	int i;
296
297	if (!init_server(&accept_socket,port)) return(0);
298
299	if (ret != NULL)
300		{
301		*ret=accept_socket;
302		/* return(1);*/
303		}
304	for (;;)
305		{
306		if (do_accept(accept_socket,&sock,&name) == 0)
307			{
308			SHUTDOWN(accept_socket);
309			return(0);
310			}
311		i=(*cb)(name,sock, context);
312		if (name != NULL) Free(name);
313		SHUTDOWN2(sock);
314		if (i < 0)
315			{
316			SHUTDOWN2(accept_socket);
317			return(i);
318			}
319		}
320	}
321
322int init_server_long(int *sock, int port, char *ip)
323	{
324	int ret=0;
325	struct sockaddr_in server;
326	int s= -1,i;
327
328	if (!sock_init()) return(0);
329
330	memset((char *)&server,0,sizeof(server));
331	server.sin_family=AF_INET;
332	server.sin_port=htons((unsigned short)port);
333	if (ip == NULL)
334		server.sin_addr.s_addr=INADDR_ANY;
335	else
336/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
337#ifndef BIT_FIELD_LIMITS
338		memcpy(&server.sin_addr.s_addr,ip,4);
339#else
340		memcpy(&server.sin_addr,ip,4);
341#endif
342	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
343
344	if (s == INVALID_SOCKET) goto err;
345#if defined SOL_SOCKET && defined SO_REUSEADDR
346		{
347		int j = 1;
348		setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
349			   (void *) &j, sizeof j);
350		}
351#endif
352	if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
353		{
354#ifndef WINDOWS
355		perror("bind");
356#endif
357		goto err;
358		}
359	/* Make it 128 for linux */
360	if (listen(s,128) == -1) goto err;
361	i=0;
362	*sock=s;
363	ret=1;
364err:
365	if ((ret == 0) && (s != -1))
366		{
367		SHUTDOWN(s);
368		}
369	return(ret);
370	}
371
372int init_server(int *sock, int port)
373	{
374	return(init_server_long(sock, port, NULL));
375	}
376
377int do_accept(int acc_sock, int *sock, char **host)
378	{
379	int ret,i;
380	struct hostent *h1,*h2;
381	static struct sockaddr_in from;
382	int len;
383/*	struct linger ling; */
384
385	if (!sock_init()) return(0);
386
387#ifndef WINDOWS
388redoit:
389#endif
390
391	memset((char *)&from,0,sizeof(from));
392	len=sizeof(from);
393	/* Note: under VMS with SOCKETSHR the fourth parameter is currently
394	 * of type (int *) whereas under other systems it is (void *) if
395	 * you don't have a cast it will choke the compiler: if you do
396	 * have a cast then you can either go for (int *) or (void *).
397	 */
398	ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
399	if (ret == INVALID_SOCKET)
400		{
401#ifdef WINDOWS
402		i=WSAGetLastError();
403		BIO_printf(bio_err,"accept error %d\n",i);
404#else
405		if (errno == EINTR)
406			{
407			/*check_timeout(); */
408			goto redoit;
409			}
410		fprintf(stderr,"errno=%d ",errno);
411		perror("accept");
412#endif
413		return(0);
414		}
415
416/*
417	ling.l_onoff=1;
418	ling.l_linger=0;
419	i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
420	if (i < 0) { perror("linger"); return(0); }
421	i=0;
422	i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
423	if (i < 0) { perror("keepalive"); return(0); }
424*/
425
426	if (host == NULL) goto end;
427#ifndef BIT_FIELD_LIMITS
428	/* I should use WSAAsyncGetHostByName() under windows */
429	h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
430		sizeof(from.sin_addr.s_addr),AF_INET);
431#else
432	h1=gethostbyaddr((char *)&from.sin_addr,
433		sizeof(struct in_addr),AF_INET);
434#endif
435	if (h1 == NULL)
436		{
437		BIO_printf(bio_err,"bad gethostbyaddr\n");
438		*host=NULL;
439		/* return(0); */
440		}
441	else
442		{
443		if ((*host=(char *)Malloc(strlen(h1->h_name)+1)) == NULL)
444			{
445			perror("Malloc");
446			return(0);
447			}
448		strcpy(*host,h1->h_name);
449
450		h2=GetHostByName(*host);
451		if (h2 == NULL)
452			{
453			BIO_printf(bio_err,"gethostbyname failure\n");
454			return(0);
455			}
456		i=0;
457		if (h2->h_addrtype != AF_INET)
458			{
459			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
460			return(0);
461			}
462		}
463end:
464	*sock=ret;
465	return(1);
466	}
467
468int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
469	     short *port_ptr)
470	{
471	char *h,*p;
472
473	h=str;
474	p=strchr(str,':');
475	if (p == NULL)
476		{
477		BIO_printf(bio_err,"no port defined\n");
478		return(0);
479		}
480	*(p++)='\0';
481
482	if ((ip != NULL) && !host_ip(str,ip))
483		goto err;
484	if (host_ptr != NULL) *host_ptr=h;
485
486	if (!extract_port(p,port_ptr))
487		goto err;
488	return(1);
489err:
490	return(0);
491	}
492
493int host_ip(char *str, unsigned char ip[4])
494	{
495	unsigned int in[4];
496	int i;
497
498	if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
499		{
500		for (i=0; i<4; i++)
501			if (in[i] > 255)
502				{
503				BIO_printf(bio_err,"invalid IP address\n");
504				goto err;
505				}
506		ip[0]=in[0];
507		ip[1]=in[1];
508		ip[2]=in[2];
509		ip[3]=in[3];
510		}
511	else
512		{ /* do a gethostbyname */
513		struct hostent *he;
514
515		if (!sock_init()) return(0);
516
517		he=GetHostByName(str);
518		if (he == NULL)
519			{
520			BIO_printf(bio_err,"gethostbyname failure\n");
521			goto err;
522			}
523		/* cast to short because of win16 winsock definition */
524		if ((short)he->h_addrtype != AF_INET)
525			{
526			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
527			return(0);
528			}
529		ip[0]=he->h_addr_list[0][0];
530		ip[1]=he->h_addr_list[0][1];
531		ip[2]=he->h_addr_list[0][2];
532		ip[3]=he->h_addr_list[0][3];
533		}
534	return(1);
535err:
536	return(0);
537	}
538
539int extract_port(char *str, short *port_ptr)
540	{
541	int i;
542	struct servent *s;
543
544	i=atoi(str);
545	if (i != 0)
546		*port_ptr=(unsigned short)i;
547	else
548		{
549		s=getservbyname(str,"tcp");
550		if (s == NULL)
551			{
552			BIO_printf(bio_err,"getservbyname failure for %s\n",str);
553			return(0);
554			}
555		*port_ptr=ntohs((unsigned short)s->s_port);
556		}
557	return(1);
558	}
559
560#define GHBN_NUM	4
561static struct ghbn_cache_st
562	{
563	char name[128];
564	struct hostent ent;
565	unsigned long order;
566	} ghbn_cache[GHBN_NUM];
567
568static unsigned long ghbn_hits=0L;
569static unsigned long ghbn_miss=0L;
570
571static struct hostent *GetHostByName(char *name)
572	{
573	struct hostent *ret;
574	int i,lowi=0;
575	unsigned long low= (unsigned long)-1;
576
577	for (i=0; i<GHBN_NUM; i++)
578		{
579		if (low > ghbn_cache[i].order)
580			{
581			low=ghbn_cache[i].order;
582			lowi=i;
583			}
584		if (ghbn_cache[i].order > 0)
585			{
586			if (strncmp(name,ghbn_cache[i].name,128) == 0)
587				break;
588			}
589		}
590	if (i == GHBN_NUM) /* no hit*/
591		{
592		ghbn_miss++;
593		ret=gethostbyname(name);
594		if (ret == NULL) return(NULL);
595		/* else add to cache */
596		strncpy(ghbn_cache[lowi].name,name,128);
597		memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
598		ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
599		return(ret);
600		}
601	else
602		{
603		ghbn_hits++;
604		ret= &(ghbn_cache[i].ent);
605		ghbn_cache[i].order=ghbn_miss+ghbn_hits;
606		return(ret);
607		}
608	}
609
610#ifndef MSDOS
611int spawn(int argc, char **argv, int *in, int *out)
612	{
613	int pid;
614#define CHILD_READ	p1[0]
615#define CHILD_WRITE	p2[1]
616#define PARENT_READ	p2[0]
617#define PARENT_WRITE	p1[1]
618	int p1[2],p2[2];
619
620	if ((pipe(p1) < 0) || (pipe(p2) < 0)) return(-1);
621
622#ifdef VMS
623	if ((pid=vfork()) == 0)
624#else
625	if ((pid=fork()) == 0)
626#endif
627		{ /* child */
628		if (dup2(CHILD_WRITE,fileno(stdout)) < 0)
629			perror("dup2");
630		if (dup2(CHILD_WRITE,fileno(stderr)) < 0)
631			perror("dup2");
632		if (dup2(CHILD_READ,fileno(stdin)) < 0)
633			perror("dup2");
634		close(CHILD_READ);
635		close(CHILD_WRITE);
636
637		close(PARENT_READ);
638		close(PARENT_WRITE);
639		execvp(argv[0],argv);
640		perror("child");
641		exit(1);
642		}
643
644	/* parent */
645	*in= PARENT_READ;
646	*out=PARENT_WRITE;
647	close(CHILD_READ);
648	close(CHILD_WRITE);
649	return(pid);
650	}
651#endif /* MSDOS */
652
653
654#ifdef undef
655	/* Turn on synchronous sockets so that we can do a WaitForMultipleObjects
656	 * on sockets */
657	{
658	SOCKET s;
659	int optionValue = SO_SYNCHRONOUS_NONALERT;
660	int err;
661
662	err = setsockopt(
663	    INVALID_SOCKET,
664	    SOL_SOCKET,
665	    SO_OPENTYPE,
666	    (char *)&optionValue,
667	    sizeof(optionValue));
668	if (err != NO_ERROR) {
669	/* failed for some reason... */
670		BIO_printf(bio_err, "failed to setsockopt(SO_OPENTYPE, SO_SYNCHRONOUS_ALERT) - %d\n",
671			WSAGetLastError());
672		}
673	}
674#endif
675