GH271: Warning on </dev/null to CA.pl
[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         OPENSSL_free(name);
358         if (type == SOCK_STREAM)
359             SHUTDOWN2(sock);
360         if (naccept != -1)
361             naccept--;
362         if (i < 0 || naccept == 0) {
363             SHUTDOWN2(accept_socket);
364             return (i);
365         }
366     }
367 }
368
369 # ifndef NO_SYS_UN_H
370 int do_server_unix(const char *path, int *ret,
371                    int (*cb) (char *hostname, int s, int stype,
372                               unsigned char *context), unsigned char *context,
373                    int naccept)
374 {
375     int sock;
376     int accept_socket = 0;
377     int i;
378
379     if (!init_server_unix(&accept_socket, path))
380         return (0);
381
382     if (ret != NULL)
383         *ret = accept_socket;
384     for (;;) {
385         if (do_accept_unix(accept_socket, &sock) == 0) {
386             SHUTDOWN(accept_socket);
387             i = 0;
388             goto out;
389         }
390         i = (*cb) (NULL, sock, 0, context);
391         SHUTDOWN2(sock);
392         if (naccept != -1)
393             naccept--;
394         if (i < 0 || naccept == 0) {
395             SHUTDOWN2(accept_socket);
396             goto out;
397         }
398     }
399  out:
400     unlink(path);
401     return (i);
402 }
403 # endif
404
405 static int init_server_long(int *sock, int port, char *ip, int type)
406 {
407     int ret = 0;
408     struct sockaddr_in server;
409     int s = -1;
410
411     if (!ssl_sock_init())
412         return (0);
413
414     memset((char *)&server, 0, sizeof(server));
415     server.sin_family = AF_INET;
416     server.sin_port = htons((unsigned short)port);
417     if (ip == NULL)
418         server.sin_addr.s_addr = INADDR_ANY;
419     else
420 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
421 # ifndef BIT_FIELD_LIMITS
422         memcpy(&server.sin_addr.s_addr, ip, 4);
423 # else
424         memcpy(&server.sin_addr, ip, 4);
425 # endif
426
427     if (type == SOCK_STREAM)
428         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
429     else                        /* type == SOCK_DGRAM */
430         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
431
432     if (s == INVALID_SOCKET)
433         goto err;
434 # if defined SOL_SOCKET && defined SO_REUSEADDR
435     {
436         int j = 1;
437         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j);
438     }
439 # endif
440     if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
441 # ifndef OPENSSL_SYS_WINDOWS
442         perror("bind");
443 # endif
444         goto err;
445     }
446     /* Make it 128 for linux */
447     if (type == SOCK_STREAM && listen(s, 128) == -1)
448         goto err;
449     *sock = s;
450     ret = 1;
451  err:
452     if ((ret == 0) && (s != -1)) {
453         SHUTDOWN(s);
454     }
455     return (ret);
456 }
457
458 static int init_server(int *sock, int port, int type)
459 {
460     return (init_server_long(sock, port, NULL, type));
461 }
462
463 # ifndef NO_SYS_UN_H
464 static int init_server_unix(int *sock, const char *path)
465 {
466     int ret = 0;
467     struct sockaddr_un server;
468     int s = -1;
469
470     if (strlen(path) > (UNIX_PATH_MAX + 1))
471         return (0);
472     if (!ssl_sock_init())
473         return (0);
474
475     s = socket(AF_UNIX, SOCK_STREAM, 0);
476     if (s == INVALID_SOCKET)
477         goto err;
478
479     memset((char *)&server, 0, sizeof(server));
480     server.sun_family = AF_UNIX;
481     strcpy(server.sun_path, path);
482
483     if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
484 #  ifndef OPENSSL_SYS_WINDOWS
485         perror("bind");
486 #  endif
487         goto err;
488     }
489     /* Make it 128 for linux */
490     if (listen(s, 128) == -1) {
491 #  ifndef OPENSSL_SYS_WINDOWS
492         perror("listen");
493 #  endif
494         unlink(path);
495         goto err;
496     }
497     *sock = s;
498     ret = 1;
499  err:
500     if ((ret == 0) && (s != -1)) {
501         SHUTDOWN(s);
502     }
503     return (ret);
504 }
505 # endif
506
507 static int do_accept(int acc_sock, int *sock, char **host)
508 {
509     int ret;
510     struct hostent *h1, *h2;
511     static struct sockaddr_in from;
512     int len;
513 /*      struct linger ling; */
514
515     if (!ssl_sock_init())
516         return (0);
517
518 # ifndef OPENSSL_SYS_WINDOWS
519  redoit:
520 # endif
521
522     memset((char *)&from, 0, sizeof(from));
523     len = sizeof(from);
524     /*
525      * Note: under VMS with SOCKETSHR the fourth parameter is currently of
526      * type (int *) whereas under other systems it is (void *) if you don't
527      * have a cast it will choke the compiler: if you do have a cast then you
528      * can either go for (int *) or (void *).
529      */
530     ret = accept(acc_sock, (struct sockaddr *)&from, (void *)&len);
531     if (ret == INVALID_SOCKET) {
532 # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
533         int i;
534         i = WSAGetLastError();
535         BIO_printf(bio_err, "accept error %d\n", i);
536 # else
537         if (errno == EINTR) {
538             /*
539              * check_timeout();
540              */
541             goto redoit;
542         }
543         fprintf(stderr, "errno=%d ", errno);
544         perror("accept");
545 # endif
546         return (0);
547     }
548
549     if (host == NULL)
550         goto end;
551 # ifndef BIT_FIELD_LIMITS
552     /* I should use WSAAsyncGetHostByName() under windows */
553     h1 = gethostbyaddr((char *)&from.sin_addr.s_addr,
554                        sizeof(from.sin_addr.s_addr), AF_INET);
555 # else
556     h1 = gethostbyaddr((char *)&from.sin_addr,
557                        sizeof(struct in_addr), AF_INET);
558 # endif
559     if (h1 == NULL) {
560         BIO_printf(bio_err, "bad gethostbyaddr\n");
561         *host = NULL;
562         /* return(0); */
563     } else {
564         *host = app_malloc(strlen(h1->h_name) + 1, "copy hostname");
565         BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1);
566
567         h2 = GetHostByName(*host);
568         if (h2 == NULL) {
569             BIO_printf(bio_err, "gethostbyname failure\n");
570             closesocket(ret);
571             return (0);
572         }
573         if (h2->h_addrtype != AF_INET) {
574             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
575             closesocket(ret);
576             return (0);
577         }
578     }
579  end:
580     *sock = ret;
581     return (1);
582 }
583
584 # ifndef NO_SYS_UN_H
585 static int do_accept_unix(int acc_sock, int *sock)
586 {
587     int ret;
588
589     if (!ssl_sock_init())
590         return (0);
591
592  redoit:
593     ret = accept(acc_sock, NULL, NULL);
594     if (ret == INVALID_SOCKET) {
595         if (errno == EINTR) {
596             /*
597              * check_timeout();
598              */
599             goto redoit;
600         }
601         fprintf(stderr, "errno=%d ", errno);
602         perror("accept");
603         return (0);
604     }
605
606     *sock = ret;
607     return (1);
608 }
609 # endif
610
611 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
612                       unsigned short *port_ptr)
613 {
614     char *h, *p;
615
616     h = str;
617     p = strchr(str, ':');
618     if (p == NULL) {
619         BIO_printf(bio_err, "no port defined\n");
620         return (0);
621     }
622     *(p++) = '\0';
623
624     if ((ip != NULL) && !host_ip(str, ip))
625         goto err;
626     if (host_ptr != NULL)
627         *host_ptr = h;
628
629     if (!extract_port(p, port_ptr))
630         goto err;
631     return (1);
632  err:
633     return (0);
634 }
635
636 static int host_ip(const char *str, unsigned char ip[4])
637 {
638     unsigned int in[4];
639     int i;
640
641     if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) ==
642         4) {
643         for (i = 0; i < 4; i++)
644             if (in[i] > 255) {
645                 BIO_printf(bio_err, "invalid IP address\n");
646                 goto err;
647             }
648         ip[0] = in[0];
649         ip[1] = in[1];
650         ip[2] = in[2];
651         ip[3] = in[3];
652     } else {                    /* do a gethostbyname */
653         struct hostent *he;
654
655         if (!ssl_sock_init())
656             return (0);
657
658         he = GetHostByName(str);
659         if (he == NULL) {
660             BIO_printf(bio_err, "gethostbyname failure\n");
661             goto err;
662         }
663         if (he->h_addrtype != AF_INET) {
664             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
665             return (0);
666         }
667         ip[0] = he->h_addr_list[0][0];
668         ip[1] = he->h_addr_list[0][1];
669         ip[2] = he->h_addr_list[0][2];
670         ip[3] = he->h_addr_list[0][3];
671     }
672     return (1);
673  err:
674     return (0);
675 }
676
677 int extract_port(const char *str, unsigned short *port_ptr)
678 {
679     int i;
680     struct servent *s;
681
682     i = atoi(str);
683     if (i != 0)
684         *port_ptr = (unsigned short)i;
685     else {
686         s = getservbyname(str, "tcp");
687         if (s == NULL) {
688             BIO_printf(bio_err, "getservbyname failure for %s\n", str);
689             return (0);
690         }
691         *port_ptr = ntohs((unsigned short)s->s_port);
692     }
693     return (1);
694 }
695
696 # define GHBN_NUM        4
697 static struct ghbn_cache_st {
698     char name[128];
699     struct hostent ent;
700     unsigned long order;
701 } ghbn_cache[GHBN_NUM];
702
703 static unsigned long ghbn_hits = 0L;
704 static unsigned long ghbn_miss = 0L;
705
706 static struct hostent *GetHostByName(const char *name)
707 {
708     struct hostent *ret;
709     int i, lowi = 0;
710     unsigned long low = (unsigned long)-1;
711
712     for (i = 0; i < GHBN_NUM; i++) {
713         if (low > ghbn_cache[i].order) {
714             low = ghbn_cache[i].order;
715             lowi = i;
716         }
717         if (ghbn_cache[i].order > 0) {
718             if (strncmp(name, ghbn_cache[i].name, 128) == 0)
719                 break;
720         }
721     }
722     if (i == GHBN_NUM) {        /* no hit */
723         ghbn_miss++;
724         ret = gethostbyname(name);
725         if (ret == NULL)
726             return (NULL);
727         /* else add to cache */
728         if (strlen(name) < sizeof ghbn_cache[0].name) {
729             strcpy(ghbn_cache[lowi].name, name);
730             memcpy((char *)&(ghbn_cache[lowi].ent), ret,
731                    sizeof(struct hostent));
732             ghbn_cache[lowi].order = ghbn_miss + ghbn_hits;
733         }
734         return (ret);
735     } else {
736         ghbn_hits++;
737         ret = &(ghbn_cache[i].ent);
738         ghbn_cache[i].order = ghbn_miss + ghbn_hits;
739         return (ret);
740     }
741 }
742
743 #endif