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