Tidy up speed.c a little.
[openssl.git] / apps / s_socket.c
1 /* apps/s_socket.c -  socket-related functions used by s_client and s_server */
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(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
70 #define __U_INT
71 typedef 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 FLAT_INC
83 #include "e_os.h"
84 #else
85 #include "../e_os.h"
86 #endif
87
88 #ifndef OPENSSL_NO_SOCK
89
90 #if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
91 #include "netdb.h"
92 #endif
93
94 static struct hostent *GetHostByName(const char *name);
95 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
96 static void ssl_sock_cleanup(void);
97 #endif
98 static int ssl_sock_init(void);
99 static int init_client_ip(int *sock, const unsigned char ip[4], int port,
100                           int type);
101 static int init_server(int *sock, int port, int type);
102 static int init_server_long(int *sock, int port,char *ip, int type);
103 static int do_accept(int acc_sock, int *sock, char **host);
104 static int host_ip(const char *str, unsigned char ip[4]);
105 #ifndef NO_SYS_UN_H
106 static int init_server_unix(int *sock, const char *path);
107 static int do_accept_unix(int acc_sock, int *sock);
108 #endif
109
110 #ifdef OPENSSL_SYS_WIN16
111 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
112 #else
113 #define SOCKET_PROTOCOL IPPROTO_TCP
114 #endif
115
116 #if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
117 static int wsa_init_done=0;
118 #endif
119
120 #ifdef OPENSSL_SYS_WINDOWS
121 static struct WSAData wsa_state;
122 static int wsa_init_done=0;
123
124 #ifdef OPENSSL_SYS_WIN16
125 static HWND topWnd=0;
126 static FARPROC lpTopWndProc=NULL;
127 static FARPROC lpTopHookProc=NULL;
128 extern HINSTANCE _hInstance;  /* nice global CRT provides */
129
130 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
131              LPARAM lParam)
132         {
133         if (hwnd == topWnd)
134                 {
135                 switch(message)
136                         {
137                 case WM_DESTROY:
138                 case WM_CLOSE:
139                         SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
140                         ssl_sock_cleanup();
141                         break;
142                         }
143                 }
144         return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
145         }
146
147 static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
148         {
149         topWnd=hwnd;
150         return(FALSE);
151         }
152
153 #endif /* OPENSSL_SYS_WIN32 */
154 #endif /* OPENSSL_SYS_WINDOWS */
155
156 #ifdef OPENSSL_SYS_WINDOWS
157 static void ssl_sock_cleanup(void)
158         {
159         if (wsa_init_done)
160                 {
161                 wsa_init_done=0;
162 #ifndef OPENSSL_SYS_WINCE
163                 WSACancelBlockingCall();
164 #endif
165                 WSACleanup();
166                 }
167         }
168 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
169 static void sock_cleanup(void)
170     {
171     if (wsa_init_done)
172         {
173         wsa_init_done=0;
174                 WSACleanup();
175                 }
176         }
177 #endif
178
179 static int ssl_sock_init(void)
180         {
181 #ifdef WATT32
182         extern int _watt_do_exit;
183         _watt_do_exit = 0;
184         if (sock_init())
185                 return (0);
186 #elif defined(OPENSSL_SYS_WINDOWS)
187         if (!wsa_init_done)
188                 {
189                 int err;
190           
191 #ifdef SIGINT
192                 signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
193 #endif
194                 wsa_init_done=1;
195                 memset(&wsa_state,0,sizeof(wsa_state));
196                 if (WSAStartup(0x0101,&wsa_state)!=0)
197                         {
198                         err=WSAGetLastError();
199                         BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
200                         return(0);
201                         }
202
203 #ifdef OPENSSL_SYS_WIN16
204                 EnumTaskWindows(GetCurrentTask(),enumproc,0L);
205                 lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
206                 lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
207
208                 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
209 #endif /* OPENSSL_SYS_WIN16 */
210                 }
211 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
212    WORD wVerReq;
213    WSADATA wsaData;
214    int err;
215
216    if (!wsa_init_done)
217       {
218    
219 # ifdef SIGINT
220       signal(SIGINT,(void (*)(int))sock_cleanup);
221 # endif
222
223       wsa_init_done=1;
224       wVerReq = MAKEWORD( 2, 0 );
225       err = WSAStartup(wVerReq,&wsaData);
226       if (err != 0)
227          {
228          BIO_printf(bio_err,"unable to start WINSOCK2, error code=%d\n",err);
229          return(0);
230          }
231       }
232 #endif /* OPENSSL_SYS_WINDOWS */
233         return(1);
234         }
235
236 int init_client(int *sock, const char *host, int port, int type)
237         {
238         unsigned char ip[4];
239
240         ip[0] = ip[1] = ip[2] = ip[3] = 0;
241         if (!host_ip(host,&(ip[0])))
242                 return 0;
243         return init_client_ip(sock,ip,port,type);
244         }
245
246 static int init_client_ip(int *sock, const unsigned char ip[4], int port,
247                           int type)
248         {
249         unsigned long addr;
250         struct sockaddr_in them;
251         int s,i;
252
253         if (!ssl_sock_init()) return(0);
254
255         memset((char *)&them,0,sizeof(them));
256         them.sin_family=AF_INET;
257         them.sin_port=htons((unsigned short)port);
258         addr=(unsigned long)
259                 ((unsigned long)ip[0]<<24L)|
260                 ((unsigned long)ip[1]<<16L)|
261                 ((unsigned long)ip[2]<< 8L)|
262                 ((unsigned long)ip[3]);
263         them.sin_addr.s_addr=htonl(addr);
264
265         if (type == SOCK_STREAM)
266                 s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
267         else /* ( type == SOCK_DGRAM) */
268                 s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
269                         
270         if (s == INVALID_SOCKET) { perror("socket"); return(0); }
271
272 #if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
273         if (type == SOCK_STREAM)
274                 {
275                 i=0;
276                 i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
277                 if (i < 0) { closesocket(s); perror("keepalive"); return(0); }
278                 }
279 #endif
280
281         if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
282                 { closesocket(s); perror("connect"); return(0); }
283         *sock=s;
284         return(1);
285         }
286
287 #ifndef NO_SYS_UN_H
288 int init_client_unix(int *sock, const char *server)
289         {
290         struct sockaddr_un them;
291         int s;
292
293         if (strlen(server) > (UNIX_PATH_MAX + 1)) return(0);
294         if (!ssl_sock_init()) return(0);
295
296         s=socket(AF_UNIX, SOCK_STREAM, 0);
297         if (s == INVALID_SOCKET) { perror("socket"); return(0); }
298
299         memset((char *)&them,0,sizeof(them));
300         them.sun_family=AF_UNIX;
301         strcpy(them.sun_path, server);
302
303         if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1)
304                 { closesocket(s); perror("connect"); return(0); }
305         *sock=s;
306         return(1);
307         }
308 #endif
309
310 int do_server(int port, int type, int *ret,
311               int (*cb)(char *hostname, int s, int stype, unsigned char *context),
312               unsigned char *context, int naccept)
313         {
314         int sock;
315         char *name = NULL;
316         int accept_socket = 0;
317         int i;
318
319         if (!init_server(&accept_socket,port,type)) return(0);
320
321         if (ret != NULL)
322                 {
323                 *ret=accept_socket;
324                 /* return(1);*/
325                 }
326         for (;;)
327                 {
328                 if (type==SOCK_STREAM)
329                         {
330 #ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
331                         if (do_accept(accept_socket,&sock,NULL) == 0)
332 #else
333                         if (do_accept(accept_socket,&sock,&name) == 0)
334 #endif
335                                 {
336                                 SHUTDOWN(accept_socket);
337                                 return(0);
338                                 }
339                         }
340                 else
341                         sock = accept_socket;
342                 i=(*cb)(name,sock, type, context);
343                 if (name != NULL) OPENSSL_free(name);
344                 if (type==SOCK_STREAM)
345                         SHUTDOWN2(sock);
346                 if (naccept != -1)
347                         naccept--;
348                 if (i < 0 || naccept == 0)
349                         {
350                         SHUTDOWN2(accept_socket);
351                         return(i);
352                         }
353                 }
354         }
355
356 #ifndef NO_SYS_UN_H
357 int do_server_unix(const char *path, int *ret,
358                    int (*cb)(char *hostname, int s, int stype, unsigned char *context),
359                    unsigned char *context, int naccept)
360         {
361         int sock;
362         int accept_socket = 0;
363         int i;
364
365         if (!init_server_unix(&accept_socket, path)) return(0);
366
367         if (ret != NULL)
368                 *ret=accept_socket;
369         for (;;)
370                 {
371                 if (do_accept_unix(accept_socket, &sock) == 0)
372                         {
373                         SHUTDOWN(accept_socket);
374                         i = 0;
375                         goto out;
376                         }
377                 i=(*cb)(NULL, sock, 0, context);
378                 SHUTDOWN2(sock);
379                 if (naccept != -1)
380                         naccept--;
381                 if (i < 0 || naccept == 0)
382                         {
383                         SHUTDOWN2(accept_socket);
384                         goto out;
385                         }
386                 }
387 out:
388         unlink(path);
389         return(i);
390         }
391 #endif
392
393 static int init_server_long(int *sock, int port, char *ip, int type)
394         {
395         int ret=0;
396         struct sockaddr_in server;
397         int s= -1;
398
399         if (!ssl_sock_init()) return(0);
400
401         memset((char *)&server,0,sizeof(server));
402         server.sin_family=AF_INET;
403         server.sin_port=htons((unsigned short)port);
404         if (ip == NULL)
405                 server.sin_addr.s_addr=INADDR_ANY;
406         else
407 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
408 #ifndef BIT_FIELD_LIMITS
409                 memcpy(&server.sin_addr.s_addr,ip,4);
410 #else
411                 memcpy(&server.sin_addr,ip,4);
412 #endif
413         
414                 if (type == SOCK_STREAM)
415                         s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
416                 else /* type == SOCK_DGRAM */
417                         s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
418
419         if (s == INVALID_SOCKET) goto err;
420 #if defined SOL_SOCKET && defined SO_REUSEADDR
421                 {
422                 int j = 1;
423                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
424                            (void *) &j, sizeof j);
425                 }
426 #endif
427         if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
428                 {
429 #ifndef OPENSSL_SYS_WINDOWS
430                 perror("bind");
431 #endif
432                 goto err;
433                 }
434         /* Make it 128 for linux */
435         if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
436         *sock=s;
437         ret=1;
438 err:
439         if ((ret == 0) && (s != -1))
440                 {
441                 SHUTDOWN(s);
442                 }
443         return(ret);
444         }
445
446 static int init_server(int *sock, int port, int type)
447         {
448         return(init_server_long(sock, port, NULL, type));
449         }
450
451 #ifndef NO_SYS_UN_H
452 static int init_server_unix(int *sock, const char *path)
453         {
454         int ret = 0;
455         struct sockaddr_un server;
456         int s = -1;
457
458         if (strlen(path) > (UNIX_PATH_MAX + 1)) return(0);
459         if (!ssl_sock_init()) return(0);
460
461         s=socket(AF_UNIX, SOCK_STREAM, 0);
462         if (s == INVALID_SOCKET) goto err;
463
464         memset((char *)&server,0,sizeof(server));
465         server.sun_family=AF_UNIX;
466         strcpy(server.sun_path, path);
467
468         if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1)
469                 {
470 #ifndef OPENSSL_SYS_WINDOWS
471                 perror("bind");
472 #endif
473                 goto err;
474                 }
475         /* Make it 128 for linux */
476         if (listen(s,128) == -1)
477                 {
478 #ifndef OPENSSL_SYS_WINDOWS
479                 perror("listen");
480 #endif
481                 unlink(path);
482                 goto err;
483                 }
484         *sock=s;
485         ret=1;
486 err:
487         if ((ret == 0) && (s != -1))
488                 {
489                 SHUTDOWN(s);
490                 }
491         return(ret);
492         }
493 #endif
494
495 static int do_accept(int acc_sock, int *sock, char **host)
496         {
497         int ret;
498         struct hostent *h1,*h2;
499         static struct sockaddr_in from;
500         int len;
501 /*      struct linger ling; */
502
503         if (!ssl_sock_init()) return(0);
504
505 #ifndef OPENSSL_SYS_WINDOWS
506 redoit:
507 #endif
508
509         memset((char *)&from,0,sizeof(from));
510         len=sizeof(from);
511         /* Note: under VMS with SOCKETSHR the fourth parameter is currently
512          * of type (int *) whereas under other systems it is (void *) if
513          * you don't have a cast it will choke the compiler: if you do
514          * have a cast then you can either go for (int *) or (void *).
515          */
516         ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
517         if (ret == INVALID_SOCKET)
518                 {
519 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
520                 int i;
521                 i=WSAGetLastError();
522                 BIO_printf(bio_err,"accept error %d\n",i);
523 #else
524                 if (errno == EINTR)
525                         {
526                         /*check_timeout(); */
527                         goto redoit;
528                         }
529                 fprintf(stderr,"errno=%d ",errno);
530                 perror("accept");
531 #endif
532                 return(0);
533                 }
534
535 /*
536         ling.l_onoff=1;
537         ling.l_linger=0;
538         i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
539         if (i < 0) { perror("linger"); return(0); }
540         i=0;
541         i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
542         if (i < 0) { perror("keepalive"); return(0); }
543 */
544
545         if (host == NULL) goto end;
546 #ifndef BIT_FIELD_LIMITS
547         /* I should use WSAAsyncGetHostByName() under windows */
548         h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
549                 sizeof(from.sin_addr.s_addr),AF_INET);
550 #else
551         h1=gethostbyaddr((char *)&from.sin_addr,
552                 sizeof(struct in_addr),AF_INET);
553 #endif
554         if (h1 == NULL)
555                 {
556                 BIO_printf(bio_err,"bad gethostbyaddr\n");
557                 *host=NULL;
558                 /* return(0); */
559                 }
560         else
561                 {
562                 if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
563                         {
564                         perror("OPENSSL_malloc");
565                         closesocket(ret);
566                         return(0);
567                         }
568                 BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
569
570                 h2=GetHostByName(*host);
571                 if (h2 == NULL)
572                         {
573                         BIO_printf(bio_err,"gethostbyname failure\n");
574                         closesocket(ret);
575                         return(0);
576                         }
577                 if (h2->h_addrtype != AF_INET)
578                         {
579                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
580                         closesocket(ret);
581                         return(0);
582                         }
583                 }
584 end:
585         *sock=ret;
586         return(1);
587         }
588
589 #ifndef NO_SYS_UN_H
590 static int do_accept_unix(int acc_sock, int *sock)
591         {
592         int ret;
593
594         if (!ssl_sock_init()) return(0);
595
596 redoit:
597         ret=accept(acc_sock, NULL, NULL);
598         if (ret == INVALID_SOCKET)
599                 {
600                 if (errno == EINTR)
601                         {
602                         /*check_timeout(); */
603                         goto redoit;
604                         }
605                 fprintf(stderr,"errno=%d ",errno);
606                 perror("accept");
607                 return(0);
608                 }
609
610         *sock=ret;
611         return(1);
612         }
613 #endif
614
615 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
616              short *port_ptr)
617         {
618         char *h,*p;
619
620         h=str;
621         p=strchr(str,':');
622         if (p == NULL)
623                 {
624                 BIO_printf(bio_err,"no port defined\n");
625                 return(0);
626                 }
627         *(p++)='\0';
628
629         if ((ip != NULL) && !host_ip(str,ip))
630                 goto err;
631         if (host_ptr != NULL) *host_ptr=h;
632
633         if (!extract_port(p,port_ptr))
634                 goto err;
635         return(1);
636 err:
637         return(0);
638         }
639
640 static int host_ip(const char *str, unsigned char ip[4])
641         {
642         unsigned int in[4]; 
643         int i;
644
645         if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
646                 {
647                 for (i=0; i<4; i++)
648                         if (in[i] > 255)
649                                 {
650                                 BIO_printf(bio_err,"invalid IP address\n");
651                                 goto err;
652                                 }
653                 ip[0]=in[0];
654                 ip[1]=in[1];
655                 ip[2]=in[2];
656                 ip[3]=in[3];
657                 }
658         else
659                 { /* do a gethostbyname */
660                 struct hostent *he;
661
662                 if (!ssl_sock_init()) return(0);
663
664                 he=GetHostByName(str);
665                 if (he == NULL)
666                         {
667                         BIO_printf(bio_err,"gethostbyname failure\n");
668                         goto err;
669                         }
670                 /* cast to short because of win16 winsock definition */
671                 if ((short)he->h_addrtype != AF_INET)
672                         {
673                         BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
674                         return(0);
675                         }
676                 ip[0]=he->h_addr_list[0][0];
677                 ip[1]=he->h_addr_list[0][1];
678                 ip[2]=he->h_addr_list[0][2];
679                 ip[3]=he->h_addr_list[0][3];
680                 }
681         return(1);
682 err:
683         return(0);
684         }
685
686 int extract_port(const char *str, short *port_ptr)
687         {
688         int i;
689         struct servent *s;
690
691         i=atoi(str);
692         if (i != 0)
693                 *port_ptr=(unsigned short)i;
694         else
695                 {
696                 s=getservbyname(str,"tcp");
697                 if (s == NULL)
698                         {
699                         BIO_printf(bio_err,"getservbyname failure for %s\n",str);
700                         return(0);
701                         }
702                 *port_ptr=ntohs((unsigned short)s->s_port);
703                 }
704         return(1);
705         }
706
707 #define GHBN_NUM        4
708 static struct ghbn_cache_st
709         {
710         char name[128];
711         struct hostent ent;
712         unsigned long order;
713         } ghbn_cache[GHBN_NUM];
714
715 static unsigned long ghbn_hits=0L;
716 static unsigned long ghbn_miss=0L;
717
718 static struct hostent *GetHostByName(const char *name)
719         {
720         struct hostent *ret;
721         int i,lowi=0;
722         unsigned long low= (unsigned long)-1;
723
724         for (i=0; i<GHBN_NUM; i++)
725                 {
726                 if (low > ghbn_cache[i].order)
727                         {
728                         low=ghbn_cache[i].order;
729                         lowi=i;
730                         }
731                 if (ghbn_cache[i].order > 0)
732                         {
733                         if (strncmp(name,ghbn_cache[i].name,128) == 0)
734                                 break;
735                         }
736                 }
737         if (i == GHBN_NUM) /* no hit*/
738                 {
739                 ghbn_miss++;
740                 ret=gethostbyname(name);
741                 if (ret == NULL) return(NULL);
742                 /* else add to cache */
743                 if(strlen(name) < sizeof ghbn_cache[0].name)
744                         {
745                         strcpy(ghbn_cache[lowi].name,name);
746                         memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
747                         ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
748                         }
749                 return(ret);
750                 }
751         else
752                 {
753                 ghbn_hits++;
754                 ret= &(ghbn_cache[i].ent);
755                 ghbn_cache[i].order=ghbn_miss+ghbn_hits;
756                 return(ret);
757                 }
758         }
759
760 #endif