b8cc7951468660eaf35920fd028488ae95df8dc5
[openssl.git] / crypto / bio / b_sock.c
1 /* crypto/bio/b_sock.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 #ifndef NO_SOCK
60
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <errno.h>
64 #define USE_SOCKETS
65 #include "cryptlib.h"
66 #include <openssl/bio.h>
67
68 #ifdef WIN16
69 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
70 #else
71 #define SOCKET_PROTOCOL IPPROTO_TCP
72 #endif
73
74 #ifdef SO_MAXCONN
75 #define MAX_LISTEN  SOMAXCONN
76 #elif defined(SO_MAXCONN)
77 #define MAX_LISTEN  SO_MAXCONN
78 #else
79 #define MAX_LISTEN  32
80 #endif
81
82 #ifdef WINDOWS
83 static int wsa_init_done=0;
84 #endif
85
86 static unsigned long BIO_ghbn_hits=0L;
87 static unsigned long BIO_ghbn_miss=0L;
88
89 #define GHBN_NUM        4
90 static struct ghbn_cache_st
91         {
92         char name[129];
93         struct hostent *ent;
94         unsigned long order;
95         } ghbn_cache[GHBN_NUM];
96
97 static int get_ip(const char *str,unsigned char *ip);
98 static void ghbn_free(struct hostent *a);
99 static struct hostent *ghbn_dup(struct hostent *a);
100 int BIO_get_host_ip(const char *str, unsigned char *ip)
101         {
102         int i;
103         struct hostent *he;
104
105         i=get_ip(str,ip);
106         if (i > 0) return(1);
107         if (i < 0)
108                 {
109                 BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_INVALID_IP_ADDRESS);
110                 ERR_add_error_data(2,"host=",str);
111                 return(0);
112                 }
113         else
114                 { /* do a gethostbyname */
115                 if (!BIO_sock_init()) return(0);
116
117                 he=BIO_gethostbyname(str);
118                 if (he == NULL)
119                         {
120                         BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_BAD_HOSTNAME_LOOKUP);
121                         ERR_add_error_data(2,"host=",str);
122                         return(0);
123                         }
124
125                 /* cast to short because of win16 winsock definition */
126                 if ((short)he->h_addrtype != AF_INET)
127                         {
128                         BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
129                         ERR_add_error_data(2,"host=",str);
130                         return(0);
131                         }
132                 for (i=0; i<4; i++)
133                         ip[i]=he->h_addr_list[0][i];
134                 }
135         return(1);
136         }
137
138 int BIO_get_port(const char *str, unsigned short *port_ptr)
139         {
140         int i;
141         struct servent *s;
142
143         if (str == NULL)
144                 {
145                 BIOerr(BIO_F_BIO_GET_PORT,BIO_R_NO_PORT_DEFINED);
146                 return(0);
147                 }
148         i=atoi(str);
149         if (i != 0)
150                 *port_ptr=(unsigned short)i;
151         else
152                 {
153                 s=getservbyname(str,"tcp");
154                 if (s == NULL)
155                         {
156                         if (strcmp(str,"http") == 0)
157                                 *port_ptr=80;
158                         else if (strcmp(str,"telnet") == 0)
159                                 *port_ptr=23;
160                         else if (strcmp(str,"socks") == 0)
161                                 *port_ptr=1080;
162                         else if (strcmp(str,"https") == 0)
163                                 *port_ptr=443;
164                         else if (strcmp(str,"ssl") == 0)
165                                 *port_ptr=443;
166                         else if (strcmp(str,"ftp") == 0)
167                                 *port_ptr=21;
168                         else if (strcmp(str,"gopher") == 0)
169                                 *port_ptr=70;
170 #if 0
171                         else if (strcmp(str,"wais") == 0)
172                                 *port_ptr=21;
173 #endif
174                         else
175                                 {
176                                 SYSerr(SYS_F_GETSERVBYNAME,get_last_socket_error());
177                                 ERR_add_error_data(3,"service='",str,"'");
178                                 return(0);
179                                 }
180                         return(1);
181                         }
182                 *port_ptr=htons((unsigned short)s->s_port);
183                 }
184         return(1);
185         }
186
187 int BIO_sock_error(int sock)
188         {
189         int j,i;
190         int size;
191                  
192         size=sizeof(int);
193         /* Note: under Windows the third parameter is of type (char *)
194          * whereas under other systems it is (void *) if you don't have
195          * a cast it will choke the compiler: if you do have a cast then
196          * you can either go for (char *) or (void *).
197          */
198         i=getsockopt(sock,SOL_SOCKET,SO_ERROR,(void *)&j,(void *)&size);
199         if (i < 0)
200                 return(1);
201         else
202                 return(j);
203         }
204
205 long BIO_ghbn_ctrl(int cmd, int iarg, char *parg)
206         {
207         int i;
208         char **p;
209
210         switch (cmd)
211                 {
212         case BIO_GHBN_CTRL_HITS:
213                 return(BIO_ghbn_hits);
214                 /* break; */
215         case BIO_GHBN_CTRL_MISSES:
216                 return(BIO_ghbn_miss);
217                 /* break; */
218         case BIO_GHBN_CTRL_CACHE_SIZE:
219                 return(GHBN_NUM);
220                 /* break; */
221         case BIO_GHBN_CTRL_GET_ENTRY:
222                 if ((iarg >= 0) && (iarg <GHBN_NUM) &&
223                         (ghbn_cache[iarg].order > 0))
224                         {
225                         p=(char **)parg;
226                         if (p == NULL) return(0);
227                         *p=ghbn_cache[iarg].name;
228                         ghbn_cache[iarg].name[128]='\0';
229                         return(1);
230                         }
231                 return(0);
232                 /* break; */
233         case BIO_GHBN_CTRL_FLUSH:
234                 for (i=0; i<GHBN_NUM; i++)
235                         ghbn_cache[i].order=0;
236                 break;
237         default:
238                 return(0);
239                 }
240         return(1);
241         }
242
243 static struct hostent *ghbn_dup(struct hostent *a)
244         {
245         struct hostent *ret;
246         int i,j;
247
248         MemCheck_off();
249         ret=(struct hostent *)Malloc(sizeof(struct hostent));
250         if (ret == NULL) return(NULL);
251         memset(ret,0,sizeof(struct hostent));
252
253         for (i=0; a->h_aliases[i] != NULL; i++)
254                 ;
255         i++;
256         ret->h_aliases=(char **)Malloc(sizeof(char *)*i);
257         memset(ret->h_aliases,0,sizeof(char *)*i);
258         if (ret == NULL) goto err;
259
260         for (i=0; a->h_addr_list[i] != NULL; i++)
261                 ;
262         i++;
263         ret->h_addr_list=(char **)Malloc(sizeof(char *)*i);
264         memset(ret->h_addr_list,0,sizeof(char *)*i);
265         if (ret->h_addr_list == NULL) goto err;
266
267         j=strlen(a->h_name)+1;
268         if ((ret->h_name=Malloc(j)) == NULL) goto err;
269         memcpy((char *)ret->h_name,a->h_name,j+1);
270         for (i=0; a->h_aliases[i] != NULL; i++)
271                 {
272                 j=strlen(a->h_aliases[i])+1;
273                 if ((ret->h_aliases[i]=Malloc(j)) == NULL) goto err;
274                 memcpy(ret->h_aliases[i],a->h_aliases[i],j+1);
275                 }
276         ret->h_length=a->h_length;
277         ret->h_addrtype=a->h_addrtype;
278         for (i=0; a->h_addr_list[i] != NULL; i++)
279                 {
280                 if ((ret->h_addr_list[i]=Malloc(a->h_length)) == NULL)
281                         goto err;
282                 memcpy(ret->h_addr_list[i],a->h_addr_list[i],a->h_length);
283                 }
284         if (0)
285                 {
286 err:    
287                 if (ret != NULL)
288                         ghbn_free(ret);
289                 ret=NULL;
290                 }
291         MemCheck_on();
292         return(ret);
293         }
294
295 static void ghbn_free(struct hostent *a)
296         {
297         int i;
298
299         if(a == NULL)
300             return;
301
302         if (a->h_aliases != NULL)
303                 {
304                 for (i=0; a->h_aliases[i] != NULL; i++)
305                         Free(a->h_aliases[i]);
306                 Free(a->h_aliases);
307                 }
308         if (a->h_addr_list != NULL)
309                 {
310                 for (i=0; a->h_addr_list[i] != NULL; i++)
311                         Free(a->h_addr_list[i]);
312                 Free(a->h_addr_list);
313                 }
314         if (a->h_name != NULL) Free((char *)a->h_name);
315         Free(a);
316         }
317
318 struct hostent *BIO_gethostbyname(const char *name)
319         {
320         struct hostent *ret;
321         int i,lowi=0,j;
322         unsigned long low= (unsigned long)-1;
323
324 /*      return(gethostbyname(name)); */
325
326         CRYPTO_w_lock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
327         j=strlen(name);
328         if (j < 128)
329                 {
330                 for (i=0; i<GHBN_NUM; i++)
331                         {
332                         if (low > ghbn_cache[i].order)
333                                 {
334                                 low=ghbn_cache[i].order;
335                                 lowi=i;
336                                 }
337                         if (ghbn_cache[i].order > 0)
338                                 {
339                                 if (strncmp(name,ghbn_cache[i].name,128) == 0)
340                                         break;
341                                 }
342                         }
343                 }
344         else
345                 i=GHBN_NUM;
346
347         if (i == GHBN_NUM) /* no hit*/
348                 {
349                 BIO_ghbn_miss++;
350                 ret=gethostbyname(name);
351
352                 if (ret == NULL) return(NULL);
353                 if (j > 128) return(ret); /* too big to cache */
354
355                 /* else add to cache */
356                 if (ghbn_cache[lowi].ent != NULL)
357                         ghbn_free(ghbn_cache[lowi].ent);
358
359                 strncpy(ghbn_cache[lowi].name,name,128);
360                 ghbn_cache[lowi].ent=ghbn_dup(ret);
361                 ghbn_cache[lowi].order=BIO_ghbn_miss+BIO_ghbn_hits;
362                 }
363         else
364                 {
365                 BIO_ghbn_hits++;
366                 ret= ghbn_cache[i].ent;
367                 ghbn_cache[i].order=BIO_ghbn_miss+BIO_ghbn_hits;
368                 }
369         CRYPTO_w_unlock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
370         return(ret);
371         }
372
373 int BIO_sock_init(void)
374         {
375 #ifdef WINDOWS
376         static struct WSAData wsa_state;
377
378         if (!wsa_init_done)
379                 {
380                 int err;
381           
382 #ifdef SIGINT
383                 signal(SIGINT,(void (*)(int))BIO_sock_cleanup);
384 #endif
385                 wsa_init_done=1;
386                 memset(&wsa_state,0,sizeof(wsa_state));
387                 if (WSAStartup(0x0101,&wsa_state)!=0)
388                         {
389                         err=WSAGetLastError();
390                         SYSerr(SYS_F_WSASTARTUP,err);
391                         BIOerr(BIO_F_BIO_SOCK_INIT,BIO_R_WSASTARTUP);
392                         return(-1);
393                         }
394                 }
395 #endif /* WINDOWS */
396         return(1);
397         }
398
399 void BIO_sock_cleanup(void)
400         {
401 #ifdef WINDOWS
402         if (wsa_init_done)
403                 {
404                 wsa_init_done=0;
405                 WSACancelBlockingCall();
406                 WSACleanup();
407                 }
408 #endif
409         }
410
411 #if !defined(VMS) || __VMS_VER >= 70000000
412
413 int BIO_socket_ioctl(int fd, long type, unsigned long *arg)
414         {
415         int i;
416
417         i=ioctlsocket(fd,type,arg);
418         if (i < 0)
419                 SYSerr(SYS_F_IOCTLSOCKET,get_last_socket_error());
420         return(i);
421         }
422 #endif /* __VMS_VER */
423
424 /* The reason I have implemented this instead of using sscanf is because
425  * Visual C 1.52c gives an unresolved external when linking a DLL :-( */
426 static int get_ip(const char *str, unsigned char ip[4])
427         {
428         unsigned int tmp[4];
429         int num=0,c,ok=0;
430
431         tmp[0]=tmp[1]=tmp[2]=tmp[3]=0;
432
433         for (;;)
434                 {
435                 c= *(str++);
436                 if ((c >= '0') && (c <= '9'))
437                         {
438                         ok=1;
439                         tmp[num]=tmp[num]*10+c-'0';
440                         if (tmp[num] > 255) return(-1);
441                         }
442                 else if (c == '.')
443                         {
444                         if (!ok) return(-1);
445                         if (num == 3) break;
446                         num++;
447                         ok=0;
448                         }
449                 else if ((num == 3) && ok)
450                         break;
451                 else
452                         return(0);
453                 }
454         ip[0]=tmp[0];
455         ip[1]=tmp[1];
456         ip[2]=tmp[2];
457         ip[3]=tmp[3];
458         return(1);
459         }
460
461 int BIO_get_accept_socket(char *host, int bind_mode)
462         {
463         int ret=0;
464         struct sockaddr_in server,client;
465         int s= -1,cs;
466         unsigned char ip[4];
467         unsigned short port;
468         char *str,*e;
469         const char *h,*p;
470         unsigned long l;
471         int err_num;
472
473         if (!BIO_sock_init()) return(INVALID_SOCKET);
474
475         if ((str=BUF_strdup(host)) == NULL) return(INVALID_SOCKET);
476
477         h=p=NULL;
478         h=str;
479         for (e=str; *e; e++)
480                 {
481                 if (*e == ':')
482                         {
483                         p= &(e[1]);
484                         *e='\0';
485                         }
486                 else if (*e == '/')
487                         {
488                         *e='\0';
489                         break;
490                         }
491                 }
492
493         if (p == NULL)
494                 {
495                 p=h;
496                 h="*";
497                 }
498
499         if (!BIO_get_port(p,&port)) return(INVALID_SOCKET);
500
501         memset((char *)&server,0,sizeof(server));
502         server.sin_family=AF_INET;
503         server.sin_port=htons(port);
504
505         if (strcmp(h,"*") == 0)
506                 server.sin_addr.s_addr=INADDR_ANY;
507         else
508                 {
509                 if (!BIO_get_host_ip(h,&(ip[0]))) return(INVALID_SOCKET);
510                 l=(unsigned long)
511                         ((unsigned long)ip[0]<<24L)|
512                         ((unsigned long)ip[1]<<16L)|
513                         ((unsigned long)ip[2]<< 8L)|
514                         ((unsigned long)ip[3]);
515                 server.sin_addr.s_addr=htonl(l);
516                 }
517
518 again:
519         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
520         if (s == INVALID_SOCKET)
521                 {
522                 SYSerr(SYS_F_SOCKET,get_last_socket_error());
523                 ERR_add_error_data(3,"port='",host,"'");
524                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_CREATE_SOCKET);
525                 goto err;
526                 }
527
528 #ifdef SO_REUSEADDR
529         if (bind_mode == BIO_BIND_REUSEADDR)
530                 {
531                 int i=1;
532
533                 ret=setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&i,sizeof(i));
534                 bind_mode=BIO_BIND_NORMAL;
535                 }
536 #endif
537         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
538                 {
539 #ifdef SO_REUSEADDR
540                 err_num=get_last_socket_error();
541                 if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
542                         (err_num == EADDRINUSE))
543                         {
544                         memcpy((char *)&client,(char *)&server,sizeof(server));
545                         if (strcmp(h,"*") == 0)
546                                 client.sin_addr.s_addr=htonl(0x7F000001);
547                         cs=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
548                         if (cs != INVALID_SOCKET)
549                                 {
550                                 int ii;
551                                 ii=connect(cs,(struct sockaddr *)&client,
552                                         sizeof(client));
553                                 closesocket(cs);
554                                 if (ii == INVALID_SOCKET)
555                                         {
556                                         bind_mode=BIO_BIND_REUSEADDR;
557                                         closesocket(s);
558                                         goto again;
559                                         }
560                                 /* else error */
561                                 }
562                         /* else error */
563                         }
564 #endif
565                 SYSerr(SYS_F_BIND,err_num);
566                 ERR_add_error_data(3,"port='",host,"'");
567                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
568                 goto err;
569                 }
570         if (listen(s,MAX_LISTEN) == -1)
571                 {
572                 SYSerr(SYS_F_BIND,get_last_socket_error());
573                 ERR_add_error_data(3,"port='",host,"'");
574                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
575                 goto err;
576                 }
577         ret=1;
578 err:
579         if (str != NULL) Free(str);
580         if ((ret == 0) && (s != INVALID_SOCKET))
581                 {
582                 closesocket(s);
583                 s= INVALID_SOCKET;
584                 }
585         return(s);
586         }
587
588 int BIO_accept(int sock, char **addr)
589         {
590         int ret=INVALID_SOCKET;
591         static struct sockaddr_in from;
592         unsigned long l;
593         unsigned short port;
594         int len;
595         char *p;
596
597         memset((char *)&from,0,sizeof(from));
598         len=sizeof(from);
599         /* Note: under VMS with SOCKETSHR the fourth parameter is currently
600          * of type (int *) whereas under other systems it is (void *) if
601          * you don't have a cast it will choke the compiler: if you do
602          * have a cast then you can either go for (int *) or (void *).
603          */
604         ret=accept(sock,(struct sockaddr *)&from,(void *)&len);
605         if (ret == INVALID_SOCKET)
606                 {
607                 SYSerr(SYS_F_ACCEPT,get_last_socket_error());
608                 BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
609                 goto end;
610                 }
611
612         if (addr == NULL) goto end;
613
614         l=ntohl(from.sin_addr.s_addr);
615         port=ntohs(from.sin_port);
616         if (*addr == NULL)
617                 {
618                 if ((p=Malloc(24)) == NULL)
619                         {
620                         BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
621                         goto end;
622                         }
623                 *addr=p;
624                 }
625         sprintf(*addr,"%d.%d.%d.%d:%d",
626                 (unsigned char)(l>>24L)&0xff,
627                 (unsigned char)(l>>16L)&0xff,
628                 (unsigned char)(l>> 8L)&0xff,
629                 (unsigned char)(l     )&0xff,
630                 port);
631 end:
632         return(ret);
633         }
634
635 int BIO_set_tcp_ndelay(int s, int on)
636         {
637         int ret=0;
638 #if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP))
639         int opt;
640
641 #ifdef SOL_TCP
642         opt=SOL_TCP;
643 #else
644 #ifdef IPPROTO_TCP
645         opt=IPPROTO_TCP;
646 #endif
647 #endif
648         
649         ret=setsockopt(s,opt,TCP_NODELAY,(char *)&on,sizeof(on));
650 #endif
651         return(ret == 0);
652         }
653 #endif
654
655 int BIO_socket_nbio(int s, int mode)
656         {
657         int ret= -1;
658         unsigned long l;
659
660         l=mode;
661 #ifdef FIONBIO
662         ret=BIO_socket_ioctl(s,FIONBIO,&l);
663 #endif
664         return(ret == 0);
665         }