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