This commit was generated by cvs2svn to track changes on a CVS vendor
[openssl.git] / crypto / bio / b_sock.c
1 /* crypto/bio/b_sock.c */
2 /* Copyright (C) 1995-1997 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 <errno.h>
63 #define USE_SOCKETS
64 #include "cryptlib.h"
65 #include "bio.h"
66
67 /*      BIOerr(BIO_F_WSASTARTUP,BIO_R_WSASTARTUP ); */
68
69 #ifdef WIN16
70 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
71 #else
72 #define SOCKET_PROTOCOL IPPROTO_TCP
73 #endif
74
75 #ifdef WINDOWS
76 static int wsa_init_done=0;
77 #endif
78
79 unsigned long BIO_ghbn_hits=0L;
80 unsigned long BIO_ghbn_miss=0L;
81
82 #ifndef NOPROTO
83 static int get_ip(char *str,unsigned char *ip);
84 #else
85 static int get_ip();
86 #endif
87
88 int BIO_get_host_ip(str,ip)
89 char *str;
90 unsigned char *ip;
91         {
92         int i;
93         struct hostent *he;
94
95         i=get_ip(str,ip);
96         if (i > 0) return(1);
97         if (i < 0)
98                 {
99                 BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_INVALID_IP_ADDRESS);
100                 return(0);
101                 }
102         else
103                 { /* do a gethostbyname */
104                 if (!BIO_sock_init()) return(0);
105
106                 he=BIO_gethostbyname(str);
107                 if (he == NULL)
108                         {
109                         BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_BAD_HOSTNAME_LOOKUP);
110                         return(0);
111                         }
112
113                 /* cast to short because of win16 winsock definition */
114                 if ((short)he->h_addrtype != AF_INET)
115                         {
116                         BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
117                         return(0);
118                         }
119                 for (i=0; i<4; i++)
120                         ip[i]=he->h_addr_list[0][i];
121                 }
122         return(1);
123         }
124
125 int BIO_get_port(str,port_ptr)
126 char *str;
127 short *port_ptr;
128         {
129         int i;
130         struct servent *s;
131
132         if (str == NULL)
133                 {
134                 BIOerr(BIO_F_BIO_GET_PORT,BIO_R_NO_PORT_DEFINED);
135                 return(0);
136                 }
137         i=atoi(str);
138         if (i != 0)
139                 *port_ptr=(unsigned short)i;
140         else
141                 {
142                 s=getservbyname(str,"tcp");
143                 if (s == NULL)
144                         {
145                         if (strcmp(str,"http") == 0)
146                                 *port_ptr=80;
147                         else if (strcmp(str,"telnet") == 0)
148                                 *port_ptr=23;
149                         else if (strcmp(str,"socks") == 0)
150                                 *port_ptr=1080;
151                         else if (strcmp(str,"https") == 0)
152                                 *port_ptr=443;
153                         else if (strcmp(str,"ssl") == 0)
154                                 *port_ptr=443;
155                         else if (strcmp(str,"ftp") == 0)
156                                 *port_ptr=21;
157                         else if (strcmp(str,"gopher") == 0)
158                                 *port_ptr=70;
159 #if 0
160                         else if (strcmp(str,"wais") == 0)
161                                 *port_ptr=21;
162 #endif
163                         else
164                                 {
165                                 SYSerr(SYS_F_GETSERVBYNAME,errno);
166                                 return(0);
167                                 }
168                         return(1);
169                         }
170                 *port_ptr=htons((unsigned short)s->s_port);
171                 }
172         return(1);
173         }
174
175 int BIO_sock_error(sock)
176 int sock;
177         {
178         int j,i,size;
179                  
180         size=sizeof(int);
181
182         i=getsockopt(sock,SOL_SOCKET,SO_ERROR,(char *)&j,&size);
183         if (i < 0)
184                 return(1);
185         else
186                 return(j);
187         }
188
189 #define GHBN_NUM        4
190 static struct ghbn_cache_st
191         {
192         char name[128];
193         struct hostent ent;
194         unsigned long order;
195         } ghbn_cache[GHBN_NUM];
196
197 struct hostent *BIO_gethostbyname(name)
198 char *name;
199         {
200         struct hostent *ret;
201         int i,lowi=0;
202         unsigned long low= (unsigned long)-1;
203
204         CRYPTO_w_lock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
205         if (strlen(name) < 128)
206                 {
207                 for (i=0; i<GHBN_NUM; i++)
208                         {
209                         if (low > ghbn_cache[i].order)
210                                 {
211                                 low=ghbn_cache[i].order;
212                                 lowi=i;
213                                 }
214                         if (ghbn_cache[i].order > 0)
215                                 {
216                                 if (strncmp(name,ghbn_cache[i].name,128) == 0)
217                                         break;
218                                 }
219                         }
220                 }
221         else
222                 i=GHBN_NUM;
223
224         if (i == GHBN_NUM) /* no hit*/
225                 {
226                 BIO_ghbn_miss++;
227                 ret=gethostbyname(name);
228                 if (ret == NULL) return(NULL);
229                 /* else add to cache */
230                 strncpy(ghbn_cache[lowi].name,name,128);
231                 memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
232                 ghbn_cache[lowi].order=BIO_ghbn_miss+BIO_ghbn_hits;
233                 }
234         else
235                 {
236                 BIO_ghbn_hits++;
237                 ret= &(ghbn_cache[i].ent);
238                 ghbn_cache[i].order=BIO_ghbn_miss+BIO_ghbn_hits;
239                 }
240         CRYPTO_w_unlock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
241         return(ret);
242         }
243
244 int BIO_sock_init()
245         {
246 #ifdef WINDOWS
247         static struct WSAData wsa_state;
248
249         if (!wsa_init_done)
250                 {
251                 int err;
252           
253 #ifdef SIGINT
254                 signal(SIGINT,(void (*)(int))BIO_sock_cleanup);
255 #endif
256                 wsa_init_done=1;
257                 memset(&wsa_state,0,sizeof(wsa_state));
258                 if (WSAStartup(0x0101,&wsa_state)!=0)
259                         {
260                         err=WSAGetLastError();
261                         SYSerr(SYS_F_WSASTARTUP,err);
262                         BIOerr(BIO_F_BIO_SOCK_INIT,BIO_R_WSASTARTUP);
263                         return(-1);
264                         }
265                 }
266 #endif /* WINDOWS */
267         return(1);
268         }
269
270 void BIO_sock_cleanup()
271         {
272 #ifdef WINDOWS
273         if (wsa_init_done)
274                 {
275                 wsa_init_done=0;
276                 WSACancelBlockingCall();
277                 WSACleanup();
278                 }
279 #endif
280         }
281
282 int BIO_socket_ioctl(fd,type,arg)
283 int fd;
284 long type;
285 unsigned long *arg;
286         {
287         int i,err;
288
289 #ifdef WINDOWS
290         i=ioctlsocket(fd,type,arg);
291 #else
292         i=ioctl(fd,type,arg);
293 #endif
294         if (i < 0)
295                 {
296 #ifdef WINDOWS
297                 err=WSAGetLastError();
298 #else
299                 err=errno;
300 #endif
301                 SYSerr(SYS_F_IOCTLSOCKET,err);
302                 }
303         return(i);
304         }
305
306 /* The reason I have implemented this instead of using sscanf is because
307  * Visual C 1.52c gives an unresolved external when linking a DLL :-( */
308 static int get_ip(str,ip)
309 char *str;
310 unsigned char ip[4];
311         {
312         unsigned int tmp[4];
313         int num=0,c,ok=0;
314
315         tmp[0]=tmp[1]=tmp[2]=tmp[3]=0;
316
317         for (;;)
318                 {
319                 c= *(str++);
320                 if ((c >= '0') && (c <= '9'))
321                         {
322                         ok=1;
323                         tmp[num]=tmp[num]*10+c-'0';
324                         if (tmp[num] > 255) return(-1);
325                         }
326                 else if (c == '.')
327                         {
328                         if (!ok) return(-1);
329                         if (num == 3) break;
330                         num++;
331                         ok=0;
332                         }
333                 else if ((num == 3) && ok)
334                         break;
335                 else
336                         return(0);
337                 }
338         ip[0]=tmp[0];
339         ip[1]=tmp[1];
340         ip[2]=tmp[2];
341         ip[3]=tmp[3];
342         return(1);
343         }
344
345 int BIO_get_accept_socket(host)
346 char *host;
347         {
348         int ret=0;
349         struct sockaddr_in server;
350         int s= -1;
351         unsigned char ip[4];
352         short port;
353         char *str,*h,*p,*e;
354         unsigned long l;
355
356         if (!BIO_sock_init()) return(INVALID_SOCKET);
357
358         if ((str=BUF_strdup(host)) == NULL) return(INVALID_SOCKET);
359
360         h=p=NULL;
361         h=str;
362         for (e=str; *e; e++)
363                 {
364                 if (*e == ':')
365                         {
366                         p= &(e[1]);
367                         *e='\0';
368                         }
369                 else if (*e == '/')
370                         {
371                         *e='\0';
372                         break;
373                         }
374                 }
375
376         if (p == NULL)
377                 {
378                 p=h;
379                 h="*";
380                 }
381
382         if (!BIO_get_port(p,&port)) return(INVALID_SOCKET);
383
384         memset((char *)&server,0,sizeof(server));
385         server.sin_family=AF_INET;
386         server.sin_port=htons((unsigned short)port);
387
388         if (strcmp(h,"*") == 0)
389                 server.sin_addr.s_addr=INADDR_ANY;
390         else
391                 {
392                 if (!BIO_get_host_ip(h,&(ip[0]))) return(INVALID_SOCKET);
393                 l=(unsigned long)
394                         ((unsigned long)ip[0]<<24L)|
395                         ((unsigned long)ip[0]<<16L)|
396                         ((unsigned long)ip[0]<< 8L)|
397                         ((unsigned long)ip[0]);
398                 server.sin_addr.s_addr=htonl(l);
399                 }
400
401         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
402         if (s == INVALID_SOCKET)
403                 {
404 #ifdef WINDOWS
405                 errno=WSAGetLastError();
406 #endif
407                 SYSerr(SYS_F_SOCKET,errno);
408                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
409                 goto err;
410                 }
411         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
412                 {
413 #ifdef WINDOWS
414                 errno=WSAGetLastError();
415 #endif
416                 SYSerr(SYS_F_BIND,errno);
417                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
418                 goto err;
419                 }
420         if (listen(s,5) == -1)
421                 {
422 #ifdef WINDOWS
423                 errno=WSAGetLastError();
424 #endif
425                 SYSerr(SYS_F_LISTEN,errno);
426                 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
427                 goto err;
428                 }
429         ret=1;
430 err:
431         if (str != NULL) Free(str);
432         if ((ret == 0) && (s != INVALID_SOCKET))
433                 {
434 #ifdef WINDOWS
435                 closesocket(s);
436 #else
437                 close(s);
438 #endif
439                 s= INVALID_SOCKET;
440                 }
441         return(s);
442         }
443
444 int BIO_accept(sock,addr)
445 int sock;
446 char **addr;
447         {
448         int ret=INVALID_SOCKET;
449         static struct sockaddr_in from;
450         unsigned long l;
451         short port;
452         int len;
453         char *p;
454
455         memset((char *)&from,0,sizeof(from));
456         len=sizeof(from);
457         ret=accept(sock,(struct sockaddr *)&from,&len);
458         if (ret == INVALID_SOCKET)
459                 {
460 #ifdef WINDOWS
461                 errno=WSAGetLastError();
462 #endif
463                 SYSerr(SYS_F_ACCEPT,errno);
464                 BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
465                 goto end;
466                 }
467
468         if (addr == NULL) goto end;
469
470         l=ntohl(from.sin_addr.s_addr);
471         port=ntohs(from.sin_port);
472         if (*addr == NULL)
473                 {
474                 if ((p=Malloc(24)) == NULL)
475                         {
476                         BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
477                         goto end;
478                         }
479                 *addr=p;
480                 }
481         sprintf(*addr,"%d.%d.%d.%d:%d",
482                 (unsigned char)(l>>24L)&0xff,
483                 (unsigned char)(l>>16L)&0xff,
484                 (unsigned char)(l>> 8L)&0xff,
485                 (unsigned char)(l     )&0xff,
486                 port);
487 end:
488         return(ret);
489         }
490
491 int BIO_set_tcp_ndelay(s,on)
492 int s;
493 int on;
494         {
495         int ret=0;
496 #if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP))
497         int opt;
498
499 #ifdef SOL_TCP
500         opt=SOL_TCP;
501 #else
502 #ifdef IPPROTO_TCP
503         opt=IPPROTO_TCP;
504 #endif
505 #endif
506         
507         ret=setsockopt(s,opt,TCP_NODELAY,(char *)&on,sizeof(on));
508 #endif
509         return(ret == 0);
510         }
511 #endif
512