In apps, malloc or die
[openssl.git] / apps / s_socket.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57 /* ====================================================================
58  * Copyright (c) 199-2015 The OpenSSL Project.  All rights reserved.
59  *
60  * Redistribution and use in source and binary forms, with or without
61  * modification, are permitted provided that the following conditions
62  * are met:
63  *
64  * 1. Redistributions of source code must retain the above copyright
65  *    notice, this list of conditions and the following disclaimer.
66  *
67  * 2. Redistributions in binary form must reproduce the above copyright
68  *    notice, this list of conditions and the following disclaimer in
69  *    the documentation and/or other materials provided with the
70  *    distribution.
71  *
72  * 3. All advertising materials mentioning features or use of this
73  *    software must display the following acknowledgment:
74  *    "This product includes software developed by the OpenSSL Project
75  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
76  *
77  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
78  *    endorse or promote products derived from this software without
79  *    prior written permission. For written permission, please contact
80  *    licensing@OpenSSL.org.
81  *
82  * 5. Products derived from this software may not be called "OpenSSL"
83  *    nor may "OpenSSL" appear in their names without prior written
84  *    permission of the OpenSSL Project.
85  *
86  * 6. Redistributions of any form whatsoever must retain the following
87  *    acknowledgment:
88  *    "This product includes software developed by the OpenSSL Project
89  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
90  *
91  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
92  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
94  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
95  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
96  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
97  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
98  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
100  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
101  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
102  * OF THE POSSIBILITY OF SUCH DAMAGE.
103  * ====================================================================
104  */
105
106 /* socket-related functions used by s_client and s_server */
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include <errno.h>
111 #include <signal.h>
112
113 /*
114  * With IPv6, it looks like Digital has mixed up the proper order of
115  * recursive header file inclusion, resulting in the compiler complaining
116  * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is
117  * needed to have fileno() declared correctly...  So let's define u_int
118  */
119 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
120 # define __U_INT
121 typedef unsigned int u_int;
122 #endif
123
124 #define USE_SOCKETS
125 #include "apps.h"
126 #undef USE_SOCKETS
127 #include "s_apps.h"
128 #include <openssl/ssl.h>
129
130 #ifdef FLAT_INC
131 # include "e_os.h"
132 #else
133 # include "../e_os.h"
134 #endif
135
136 #ifndef OPENSSL_NO_SOCK
137
138 # if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
139 #  include "netdb.h"
140 # endif
141
142 static struct hostent *GetHostByName(const char *name);
143 # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
144 static void ssl_sock_cleanup(void);
145 # endif
146 static int ssl_sock_init(void);
147 static int init_client_ip(int *sock, const unsigned char ip[4], int port,
148                           int type);
149 static int init_server(int *sock, int port, int type);
150 static int init_server_long(int *sock, int port, char *ip, int type);
151 static int do_accept(int acc_sock, int *sock, char **host);
152 static int host_ip(const char *str, unsigned char ip[4]);
153 # ifndef NO_SYS_UN_H
154 static int init_server_unix(int *sock, const char *path);
155 static int do_accept_unix(int acc_sock, int *sock);
156 # endif
157
158 # if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
159 static int wsa_init_done = 0;
160 # endif
161
162 # ifdef OPENSSL_SYS_WINDOWS
163 static struct WSAData wsa_state;
164 static int wsa_init_done = 0;
165
166 # endif                         /* OPENSSL_SYS_WINDOWS */
167
168 # ifdef OPENSSL_SYS_WINDOWS
169 static void ssl_sock_cleanup(void)
170 {
171     if (wsa_init_done) {
172         wsa_init_done = 0;
173 #  ifndef OPENSSL_SYS_WINCE
174         WSACancelBlockingCall();
175 #  endif
176         WSACleanup();
177     }
178 }
179 # elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
180 static void sock_cleanup(void)
181 {
182     if (wsa_init_done) {
183         wsa_init_done = 0;
184         WSACleanup();
185     }
186 }
187 # endif
188
189 static int ssl_sock_init(void)
190 {
191 # ifdef WATT32
192     extern int _watt_do_exit;
193     _watt_do_exit = 0;
194     if (sock_init())
195         return (0);
196 # elif defined(OPENSSL_SYS_WINDOWS)
197     if (!wsa_init_done) {
198         int err;
199
200 #  ifdef SIGINT
201         signal(SIGINT, (void (*)(int))ssl_sock_cleanup);
202 #  endif
203         wsa_init_done = 1;
204         memset(&wsa_state, 0, sizeof(wsa_state));
205         if (WSAStartup(0x0101, &wsa_state) != 0) {
206             err = WSAGetLastError();
207             BIO_printf(bio_err, "unable to start WINSOCK, error code=%d\n",
208                        err);
209             return (0);
210         }
211     }
212 # elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
213     WORD wVerReq;
214     WSADATA wsaData;
215     int err;
216
217     if (!wsa_init_done) {
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             BIO_printf(bio_err, "unable to start WINSOCK2, error code=%d\n",
228                        err);
229             return (0);
230         }
231     }
232 # endif
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())
254         return (0);
255
256     memset((char *)&them, 0, sizeof(them));
257     them.sin_family = AF_INET;
258     them.sin_port = htons((unsigned short)port);
259     addr = (unsigned long)
260         ((unsigned long)ip[0] << 24L) |
261         ((unsigned long)ip[1] << 16L) |
262         ((unsigned long)ip[2] << 8L) | ((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, IPPROTO_TCP);
267     else                        /* ( type == SOCK_DGRAM) */
268         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
269
270     if (s == INVALID_SOCKET) {
271         perror("socket");
272         return (0);
273     }
274 # if defined(SO_KEEPALIVE)
275     if (type == SOCK_STREAM) {
276         i = 0;
277         i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i));
278         if (i < 0) {
279             closesocket(s);
280             perror("keepalive");
281             return (0);
282         }
283     }
284 # endif
285
286     if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) {
287         closesocket(s);
288         perror("connect");
289         return (0);
290     }
291     *sock = s;
292     return (1);
293 }
294
295 # ifndef NO_SYS_UN_H
296 int init_client_unix(int *sock, const char *server)
297 {
298     struct sockaddr_un them;
299     int s;
300
301     if (strlen(server) > (UNIX_PATH_MAX + 1))
302         return (0);
303     if (!ssl_sock_init())
304         return (0);
305
306     s = socket(AF_UNIX, SOCK_STREAM, 0);
307     if (s == INVALID_SOCKET) {
308         perror("socket");
309         return (0);
310     }
311
312     memset((char *)&them, 0, sizeof(them));
313     them.sun_family = AF_UNIX;
314     strcpy(them.sun_path, server);
315
316     if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) {
317         closesocket(s);
318         perror("connect");
319         return (0);
320     }
321     *sock = s;
322     return (1);
323 }
324 # endif
325
326 int do_server(int port, int type, int *ret,
327               int (*cb) (char *hostname, int s, int stype,
328                          unsigned char *context), unsigned char *context,
329               int naccept)
330 {
331     int sock;
332     char *name = NULL;
333     int accept_socket = 0;
334     int i;
335
336     if (!init_server(&accept_socket, port, type))
337         return (0);
338
339     if (ret != NULL) {
340         *ret = accept_socket;
341         /* return(1); */
342     }
343     for (;;) {
344         if (type == SOCK_STREAM) {
345 # ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
346             if (do_accept(accept_socket, &sock, NULL) == 0)
347 # else
348             if (do_accept(accept_socket, &sock, &name) == 0)
349 # endif
350             {
351                 SHUTDOWN(accept_socket);
352                 return (0);
353             }
354         } else
355             sock = accept_socket;
356         i = (*cb) (name, sock, type, context);
357         if (name != NULL)
358             OPENSSL_free(name);
359         if (type == SOCK_STREAM)
360             SHUTDOWN2(sock);
361         if (naccept != -1)
362             naccept--;
363         if (i < 0 || naccept == 0) {
364             SHUTDOWN2(accept_socket);
365             return (i);
366         }
367     }
368 }
369
370 # ifndef NO_SYS_UN_H
371 int do_server_unix(const char *path, int *ret,
372                    int (*cb) (char *hostname, int s, int stype,
373                               unsigned char *context), unsigned char *context,
374                    int naccept)
375 {
376     int sock;
377     int accept_socket = 0;
378     int i;
379
380     if (!init_server_unix(&accept_socket, path))
381         return (0);
382
383     if (ret != NULL)
384         *ret = accept_socket;
385     for (;;) {
386         if (do_accept_unix(accept_socket, &sock) == 0) {
387             SHUTDOWN(accept_socket);
388             i = 0;
389             goto out;
390         }
391         i = (*cb) (NULL, sock, 0, context);
392         SHUTDOWN2(sock);
393         if (naccept != -1)
394             naccept--;
395         if (i < 0 || naccept == 0) {
396             SHUTDOWN2(accept_socket);
397             goto out;
398         }
399     }
400  out:
401     unlink(path);
402     return (i);
403 }
404 # endif
405
406 static int init_server_long(int *sock, int port, char *ip, int type)
407 {
408     int ret = 0;
409     struct sockaddr_in server;
410     int s = -1;
411
412     if (!ssl_sock_init())
413         return (0);
414
415     memset((char *)&server, 0, sizeof(server));
416     server.sin_family = AF_INET;
417     server.sin_port = htons((unsigned short)port);
418     if (ip == NULL)
419         server.sin_addr.s_addr = INADDR_ANY;
420     else
421 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
422 # ifndef BIT_FIELD_LIMITS
423         memcpy(&server.sin_addr.s_addr, ip, 4);
424 # else
425         memcpy(&server.sin_addr, ip, 4);
426 # endif
427
428     if (type == SOCK_STREAM)
429         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
430     else                        /* type == SOCK_DGRAM */
431         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
432
433     if (s == INVALID_SOCKET)
434         goto err;
435 # if defined SOL_SOCKET && defined SO_REUSEADDR
436     {
437         int j = 1;
438         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j);
439     }
440 # endif
441     if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
442 # ifndef OPENSSL_SYS_WINDOWS
443         perror("bind");
444 # endif
445         goto err;
446     }
447     /* Make it 128 for linux */
448     if (type == SOCK_STREAM && listen(s, 128) == -1)
449         goto err;
450     *sock = s;
451     ret = 1;
452  err:
453     if ((ret == 0) && (s != -1)) {
454         SHUTDOWN(s);
455     }
456     return (ret);
457 }
458
459 static int init_server(int *sock, int port, int type)
460 {
461     return (init_server_long(sock, port, NULL, type));
462 }
463
464 # ifndef NO_SYS_UN_H
465 static int init_server_unix(int *sock, const char *path)
466 {
467     int ret = 0;
468     struct sockaddr_un server;
469     int s = -1;
470
471     if (strlen(path) > (UNIX_PATH_MAX + 1))
472         return (0);
473     if (!ssl_sock_init())
474         return (0);
475
476     s = socket(AF_UNIX, SOCK_STREAM, 0);
477     if (s == INVALID_SOCKET)
478         goto err;
479
480     memset((char *)&server, 0, sizeof(server));
481     server.sun_family = AF_UNIX;
482     strcpy(server.sun_path, path);
483
484     if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
485 #  ifndef OPENSSL_SYS_WINDOWS
486         perror("bind");
487 #  endif
488         goto err;
489     }
490     /* Make it 128 for linux */
491     if (listen(s, 128) == -1) {
492 #  ifndef OPENSSL_SYS_WINDOWS
493         perror("listen");
494 #  endif
495         unlink(path);
496         goto err;
497     }
498     *sock = s;
499     ret = 1;
500  err:
501     if ((ret == 0) && (s != -1)) {
502         SHUTDOWN(s);
503     }
504     return (ret);
505 }
506 # endif
507
508 static int do_accept(int acc_sock, int *sock, char **host)
509 {
510     int ret;
511     struct hostent *h1, *h2;
512     static struct sockaddr_in from;
513     int len;
514 /*      struct linger ling; */
515
516     if (!ssl_sock_init())
517         return (0);
518
519 # ifndef OPENSSL_SYS_WINDOWS
520  redoit:
521 # endif
522
523     memset((char *)&from, 0, sizeof(from));
524     len = sizeof(from);
525     /*
526      * Note: under VMS with SOCKETSHR the fourth parameter is currently of
527      * type (int *) whereas under other systems it is (void *) if you don't
528      * have a cast it will choke the compiler: if you do have a cast then you
529      * can either go for (int *) or (void *).
530      */
531     ret = accept(acc_sock, (struct sockaddr *)&from, (void *)&len);
532     if (ret == INVALID_SOCKET) {
533 # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
534         int i;
535         i = WSAGetLastError();
536         BIO_printf(bio_err, "accept error %d\n", i);
537 # else
538         if (errno == EINTR) {
539             /*
540              * check_timeout();
541              */
542             goto redoit;
543         }
544         fprintf(stderr, "errno=%d ", errno);
545         perror("accept");
546 # endif
547         return (0);
548     }
549
550     if (host == NULL)
551         goto end;
552 # ifndef BIT_FIELD_LIMITS
553     /* I should use WSAAsyncGetHostByName() under windows */
554     h1 = gethostbyaddr((char *)&from.sin_addr.s_addr,
555                        sizeof(from.sin_addr.s_addr), AF_INET);
556 # else
557     h1 = gethostbyaddr((char *)&from.sin_addr,
558                        sizeof(struct in_addr), AF_INET);
559 # endif
560     if (h1 == NULL) {
561         BIO_printf(bio_err, "bad gethostbyaddr\n");
562         *host = NULL;
563         /* return(0); */
564     } else {
565         *host = app_malloc(strlen(h1->h_name) + 1, "copy hostname");
566         BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1);
567
568         h2 = GetHostByName(*host);
569         if (h2 == NULL) {
570             BIO_printf(bio_err, "gethostbyname failure\n");
571             closesocket(ret);
572             return (0);
573         }
574         if (h2->h_addrtype != AF_INET) {
575             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
576             closesocket(ret);
577             return (0);
578         }
579     }
580  end:
581     *sock = ret;
582     return (1);
583 }
584
585 # ifndef NO_SYS_UN_H
586 static int do_accept_unix(int acc_sock, int *sock)
587 {
588     int ret;
589
590     if (!ssl_sock_init())
591         return (0);
592
593  redoit:
594     ret = accept(acc_sock, NULL, NULL);
595     if (ret == INVALID_SOCKET) {
596         if (errno == EINTR) {
597             /*
598              * check_timeout();
599              */
600             goto redoit;
601         }
602         fprintf(stderr, "errno=%d ", errno);
603         perror("accept");
604         return (0);
605     }
606
607     *sock = ret;
608     return (1);
609 }
610 # endif
611
612 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
613                       unsigned short *port_ptr)
614 {
615     char *h, *p;
616
617     h = str;
618     p = strchr(str, ':');
619     if (p == NULL) {
620         BIO_printf(bio_err, "no port defined\n");
621         return (0);
622     }
623     *(p++) = '\0';
624
625     if ((ip != NULL) && !host_ip(str, ip))
626         goto err;
627     if (host_ptr != NULL)
628         *host_ptr = h;
629
630     if (!extract_port(p, port_ptr))
631         goto err;
632     return (1);
633  err:
634     return (0);
635 }
636
637 static int host_ip(const char *str, unsigned char ip[4])
638 {
639     unsigned int in[4];
640     int i;
641
642     if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) ==
643         4) {
644         for (i = 0; i < 4; i++)
645             if (in[i] > 255) {
646                 BIO_printf(bio_err, "invalid IP address\n");
647                 goto err;
648             }
649         ip[0] = in[0];
650         ip[1] = in[1];
651         ip[2] = in[2];
652         ip[3] = in[3];
653     } else {                    /* do a gethostbyname */
654         struct hostent *he;
655
656         if (!ssl_sock_init())
657             return (0);
658
659         he = GetHostByName(str);
660         if (he == NULL) {
661             BIO_printf(bio_err, "gethostbyname failure\n");
662             goto err;
663         }
664         if (he->h_addrtype != AF_INET) {
665             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
666             return (0);
667         }
668         ip[0] = he->h_addr_list[0][0];
669         ip[1] = he->h_addr_list[0][1];
670         ip[2] = he->h_addr_list[0][2];
671         ip[3] = he->h_addr_list[0][3];
672     }
673     return (1);
674  err:
675     return (0);
676 }
677
678 int extract_port(const char *str, unsigned short *port_ptr)
679 {
680     int i;
681     struct servent *s;
682
683     i = atoi(str);
684     if (i != 0)
685         *port_ptr = (unsigned short)i;
686     else {
687         s = getservbyname(str, "tcp");
688         if (s == NULL) {
689             BIO_printf(bio_err, "getservbyname failure for %s\n", str);
690             return (0);
691         }
692         *port_ptr = ntohs((unsigned short)s->s_port);
693     }
694     return (1);
695 }
696
697 # define GHBN_NUM        4
698 static struct ghbn_cache_st {
699     char name[128];
700     struct hostent ent;
701     unsigned long order;
702 } ghbn_cache[GHBN_NUM];
703
704 static unsigned long ghbn_hits = 0L;
705 static unsigned long ghbn_miss = 0L;
706
707 static struct hostent *GetHostByName(const char *name)
708 {
709     struct hostent *ret;
710     int i, lowi = 0;
711     unsigned long low = (unsigned long)-1;
712
713     for (i = 0; i < GHBN_NUM; i++) {
714         if (low > ghbn_cache[i].order) {
715             low = ghbn_cache[i].order;
716             lowi = i;
717         }
718         if (ghbn_cache[i].order > 0) {
719             if (strncmp(name, ghbn_cache[i].name, 128) == 0)
720                 break;
721         }
722     }
723     if (i == GHBN_NUM) {        /* no hit */
724         ghbn_miss++;
725         ret = gethostbyname(name);
726         if (ret == NULL)
727             return (NULL);
728         /* else add to cache */
729         if (strlen(name) < sizeof ghbn_cache[0].name) {
730             strcpy(ghbn_cache[lowi].name, name);
731             memcpy((char *)&(ghbn_cache[lowi].ent), ret,
732                    sizeof(struct hostent));
733             ghbn_cache[lowi].order = ghbn_miss + ghbn_hits;
734         }
735         return (ret);
736     } else {
737         ghbn_hits++;
738         ret = &(ghbn_cache[i].ent);
739         ghbn_cache[i].order = ghbn_miss + ghbn_hits;
740         return (ret);
741     }
742 }
743
744 #endif