]> git.ipfire.org Git - thirdparty/openssl.git/blame - apps/s_socket.c
VMS updates.
[thirdparty/openssl.git] / apps / s_socket.c
CommitLineData
d02b48c6 1/* apps/s_socket.c */
58964a49 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
d02b48c6
RE
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
8c197cc5
UM
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <errno.h>
63#include <signal.h>
64
7d7d2cbc
UM
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 */
1e44804e 69#if defined(VMS) && defined(__DECC) && !defined(__U_INT)
7d7d2cbc
UM
70#define __U_INT
71typedef unsigned int u_int;
72#endif
73
d02b48c6
RE
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"
ec577822 80#include <openssl/ssl.h>
d02b48c6 81
75e0770d 82#ifdef VMS
7d7d2cbc
UM
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
75e0770d 87#include <processes.h> /* for vfork() */
7d7d2cbc
UM
88#endif
89
d02b48c6
RE
90static struct hostent *GetHostByName(char *name);
91int sock_init(void );
d02b48c6
RE
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
6b691a5c
UM
108static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
109 LPARAM lParam)
d02b48c6
RE
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
6b691a5c 134void sock_cleanup(void)
d02b48c6
RE
135 {
136#ifdef WINDOWS
137 if (wsa_init_done)
138 {
139 wsa_init_done=0;
140 WSACancelBlockingCall();
141 WSACleanup();
142 }
143#endif
144 }
145
6b691a5c 146int sock_init(void)
d02b48c6
RE
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
6b691a5c 177int init_client(int *sock, char *host, int port)
d02b48c6
RE
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
6b691a5c 190int init_client_ip(int *sock, unsigned char ip[4], int port)
d02b48c6
RE
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
6b691a5c 221int nbio_sock_error(int sock)
d02b48c6 222 {
95dc05bc 223 int j,i;
61f5b6f3 224 int size;
d02b48c6
RE
225
226 size=sizeof(int);
7d7d2cbc
UM
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);
d02b48c6
RE
233 if (i < 0)
234 return(1);
235 else
236 return(j);
237 }
238
6b691a5c 239int nbio_init_client_ip(int *sock, unsigned char ip[4], int port)
d02b48c6
RE
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 {
75e0770d 259#ifdef FIONBIO
d02b48c6 260 unsigned long l=1;
75e0770d 261#endif
d02b48c6
RE
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
58964a49 272 BIO_socket_ioctl(s,FIONBIO,&l);
d02b48c6
RE
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
6b691a5c 290int do_server(int port, int *ret, int (*cb)(), char *context)
d02b48c6
RE
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 }
b4cadc6e 311 i=(*cb)(name,sock, context);
d02b48c6 312 if (name != NULL) Free(name);
58964a49 313 SHUTDOWN2(sock);
d02b48c6
RE
314 if (i < 0)
315 {
58964a49 316 SHUTDOWN2(accept_socket);
d02b48c6
RE
317 return(i);
318 }
319 }
320 }
321
6b691a5c 322int init_server_long(int *sock, int port, char *ip)
d02b48c6
RE
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);
58964a49
RE
333 if (ip == NULL)
334 server.sin_addr.s_addr=INADDR_ANY;
335 else
13e91dd3
RE
336/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
337#ifndef BIT_FIELD_LIMITS
58964a49 338 memcpy(&server.sin_addr.s_addr,ip,4);
13e91dd3
RE
339#else
340 memcpy(&server.sin_addr,ip,4);
341#endif
d02b48c6
RE
342 s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
343
344 if (s == INVALID_SOCKET) goto err;
cf897932
BM
345#if defined SOL_SOCKET && defined SO_REUSEADDR
346 {
121bd68d 347 int j = 1;
f0f1b4e4 348 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
7d7d2cbc 349 (void *) &j, sizeof j);
cf897932
BM
350 }
351#endif
d02b48c6
RE
352 if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
353 {
354#ifndef WINDOWS
355 perror("bind");
356#endif
357 goto err;
358 }
58964a49
RE
359 /* Make it 128 for linux */
360 if (listen(s,128) == -1) goto err;
d02b48c6
RE
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
6b691a5c 372int init_server(int *sock, int port)
58964a49
RE
373 {
374 return(init_server_long(sock, port, NULL));
375 }
376
6b691a5c 377int do_accept(int acc_sock, int *sock, char **host)
d02b48c6
RE
378 {
379 int ret,i;
380 struct hostent *h1,*h2;
381 static struct sockaddr_in from;
61f5b6f3 382 int len;
d02b48c6
RE
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);
75e0770d 393 /* Note: under VMS with SOCKETSHR the fourth parameter is currently
7d7d2cbc
UM
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);
d02b48c6
RE
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;
58964a49 427#ifndef BIT_FIELD_LIMITS
d02b48c6
RE
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);
58964a49
RE
431#else
432 h1=gethostbyaddr((char *)&from.sin_addr,
433 sizeof(struct in_addr),AF_INET);
434#endif
d02b48c6
RE
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
6b691a5c
UM
468int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
469 short *port_ptr)
d02b48c6
RE
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
6b691a5c 493int host_ip(char *str, unsigned char ip[4])
d02b48c6
RE
494 {
495 unsigned int in[4];
496 int i;
497
d58d092b 498 if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
d02b48c6
RE
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
6b691a5c 539int extract_port(char *str, short *port_ptr)
d02b48c6
RE
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
6b691a5c 571static struct hostent *GetHostByName(char *name)
d02b48c6
RE
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
6b691a5c 611int spawn(int argc, char **argv, int *in, int *out)
d02b48c6
RE
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
7d7d2cbc
UM
622#ifdef VMS
623 if ((pid=vfork()) == 0)
624#else
d02b48c6 625 if ((pid=fork()) == 0)
7d7d2cbc 626#endif
d02b48c6
RE
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