4c440dc50a7902edd12d8cc928db80e726ea8c23
[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         if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) {
566             perror("OPENSSL_malloc");
567             closesocket(ret);
568             return (0);
569         }
570         BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1);
571
572         h2 = GetHostByName(*host);
573         if (h2 == NULL) {
574             BIO_printf(bio_err, "gethostbyname failure\n");
575             closesocket(ret);
576             return (0);
577         }
578         if (h2->h_addrtype != AF_INET) {
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())
595         return (0);
596
597  redoit:
598     ret = accept(acc_sock, NULL, NULL);
599     if (ret == INVALID_SOCKET) {
600         if (errno == EINTR) {
601             /*
602              * check_timeout();
603              */
604             goto redoit;
605         }
606         fprintf(stderr, "errno=%d ", errno);
607         perror("accept");
608         return (0);
609     }
610
611     *sock = ret;
612     return (1);
613 }
614 # endif
615
616 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
617                       unsigned short *port_ptr)
618 {
619     char *h, *p;
620
621     h = str;
622     p = strchr(str, ':');
623     if (p == NULL) {
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)
632         *host_ptr = h;
633
634     if (!extract_port(p, port_ptr))
635         goto err;
636     return (1);
637  err:
638     return (0);
639 }
640
641 static int host_ip(const char *str, unsigned char ip[4])
642 {
643     unsigned int in[4];
644     int i;
645
646     if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) ==
647         4) {
648         for (i = 0; i < 4; i++)
649             if (in[i] > 255) {
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     } else {                    /* do a gethostbyname */
658         struct hostent *he;
659
660         if (!ssl_sock_init())
661             return (0);
662
663         he = GetHostByName(str);
664         if (he == NULL) {
665             BIO_printf(bio_err, "gethostbyname failure\n");
666             goto err;
667         }
668         if (he->h_addrtype != AF_INET) {
669             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
670             return (0);
671         }
672         ip[0] = he->h_addr_list[0][0];
673         ip[1] = he->h_addr_list[0][1];
674         ip[2] = he->h_addr_list[0][2];
675         ip[3] = he->h_addr_list[0][3];
676     }
677     return (1);
678  err:
679     return (0);
680 }
681
682 int extract_port(const char *str, unsigned short *port_ptr)
683 {
684     int i;
685     struct servent *s;
686
687     i = atoi(str);
688     if (i != 0)
689         *port_ptr = (unsigned short)i;
690     else {
691         s = getservbyname(str, "tcp");
692         if (s == NULL) {
693             BIO_printf(bio_err, "getservbyname failure for %s\n", str);
694             return (0);
695         }
696         *port_ptr = ntohs((unsigned short)s->s_port);
697     }
698     return (1);
699 }
700
701 # define GHBN_NUM        4
702 static struct ghbn_cache_st {
703     char name[128];
704     struct hostent ent;
705     unsigned long order;
706 } ghbn_cache[GHBN_NUM];
707
708 static unsigned long ghbn_hits = 0L;
709 static unsigned long ghbn_miss = 0L;
710
711 static struct hostent *GetHostByName(const char *name)
712 {
713     struct hostent *ret;
714     int i, lowi = 0;
715     unsigned long low = (unsigned long)-1;
716
717     for (i = 0; i < GHBN_NUM; i++) {
718         if (low > ghbn_cache[i].order) {
719             low = ghbn_cache[i].order;
720             lowi = i;
721         }
722         if (ghbn_cache[i].order > 0) {
723             if (strncmp(name, ghbn_cache[i].name, 128) == 0)
724                 break;
725         }
726     }
727     if (i == GHBN_NUM) {        /* no hit */
728         ghbn_miss++;
729         ret = gethostbyname(name);
730         if (ret == NULL)
731             return (NULL);
732         /* else add to cache */
733         if (strlen(name) < sizeof ghbn_cache[0].name) {
734             strcpy(ghbn_cache[lowi].name, name);
735             memcpy((char *)&(ghbn_cache[lowi].ent), ret,
736                    sizeof(struct hostent));
737             ghbn_cache[lowi].order = ghbn_miss + ghbn_hits;
738         }
739         return (ret);
740     } else {
741         ghbn_hits++;
742         ret = &(ghbn_cache[i].ent);
743         ghbn_cache[i].order = ghbn_miss + ghbn_hits;
744         return (ret);
745     }
746 }
747
748 #endif