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