Add resolutions to main icon
[privoxy.git] / jbsockets.c
1 const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.24 2002/03/07 03:51:36 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
5  *
6  * Purpose     :  Contains wrappers for system-specific sockets code,
7  *                so that the rest of JunkBuster can be more
8  *                OS-independent.  Contains #ifdefs to make this work
9  *                on many platforms.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and 
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it 
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: jbsockets.c,v $
38  *    Revision 1.24  2002/03/07 03:51:36  oes
39  *     - Improved handling of failed DNS lookups
40  *     - Fixed compiler warnings etc
41  *
42  *    Revision 1.23  2002/03/05 00:36:01  jongfoster
43  *    Fixing bug 514988 - unable to restart JunkBuster
44  *
45  *    Revision 1.22  2002/03/04 02:08:02  david__schmidt
46  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
47  *
48  *    Revision 1.21  2002/01/09 14:32:33  oes
49  *    Added support for gethostbyname_r and gethostbyaddr_r.
50  *
51  *    Revision 1.20  2001/11/16 00:48:48  jongfoster
52  *    Enabling duplicate-socket detection for all platforms, not
53  *    just Win32.
54  *
55  *    Revision 1.19  2001/10/25 03:40:47  david__schmidt
56  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
57  *    threads to call select() simultaneously.  So, it's time to do a real, live,
58  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
59  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
60  *
61  *    Revision 1.18  2001/09/21 23:02:02  david__schmidt
62  *    Cleaning up 2 compiler warnings on OS/2.
63  *
64  *    Revision 1.17  2001/09/13 20:11:46  jongfoster
65  *    Fixing 2 compiler warnings under Win32
66  *
67  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
68  *    Tidying up #defines:
69  *    - All feature #defines are now of the form FEATURE_xxx
70  *    - Permanently turned off WIN_GUI_EDIT
71  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
72  *
73  *    Revision 1.15  2001/07/29 17:40:43  jongfoster
74  *    Fixed compiler warning by adding a cast
75  *
76  *    Revision 1.14  2001/07/18 13:47:59  oes
77  *    Eliminated dirty hack for getsockbyname()
78  *
79  *    Revision 1.13  2001/07/15 13:56:57  jongfoster
80  *    Removing unused local variable.
81  *
82  *    Revision 1.12  2001/07/01 17:04:11  oes
83  *    Bugfix: accept_connection no longer uses the obsolete hstrerror() function
84  *
85  *    Revision 1.11  2001/06/29 21:45:41  oes
86  *    Indentation, CRLF->LF, Tab-> Space
87  *
88  *    Revision 1.10  2001/06/29 13:29:15  oes
89  *    - Added remote (server) host IP to csp->http->host_ip_addr_str
90  *    - Added detection of local socket IP and fqdn
91  *    - Removed logentry from cancelled commit
92  *
93  *    Revision 1.9  2001/06/07 23:06:09  jongfoster
94  *    The host parameter to connect_to() is now const.
95  *
96  *    Revision 1.8  2001/06/03 19:12:07  oes
97  *    filled comment
98  *
99  *    Revision 1.7  2001/05/28 16:14:00  jongfoster
100  *    Fixing bug in LOG_LEVEL_LOG
101  *
102  *    Revision 1.6  2001/05/26 17:28:32  jongfoster
103  *    Fixed LOG_LEVEL_LOG
104  *
105  *    Revision 1.5  2001/05/26 15:26:15  jongfoster
106  *    ACL feature now provides more security by immediately dropping
107  *    connections from untrusted hosts.
108  *
109  *    Revision 1.4  2001/05/26 00:37:42  jongfoster
110  *    Cosmetic indentation correction.
111  *
112  *    Revision 1.3  2001/05/25 21:57:54  jongfoster
113  *    Now gives a warning under Windows if you try to bind
114  *    it to a port that's already in use.
115  *
116  *    Revision 1.2  2001/05/17 23:01:01  oes
117  *     - Cleaned CRLF's from the sources and related files
118  *
119  *    Revision 1.1.1.1  2001/05/15 13:58:54  oes
120  *    Initial import of version 2.9.3 source tree
121  *
122  *
123  *********************************************************************/
124 \f
125
126 #include "config.h"
127
128 #include <stdlib.h>
129 #include <stdio.h>
130 #include <string.h>
131 #include <errno.h>
132 #include <fcntl.h>
133 #include <sys/types.h>
134
135 #ifdef _WIN32
136
137 #include <windows.h>
138 #include <sys/timeb.h>
139 #include <io.h>
140
141 #else
142
143 #ifndef __OS2__
144 #include <unistd.h>
145 #endif
146 #include <sys/time.h>
147 #include <netinet/in.h>
148 #include <sys/ioctl.h>
149 #include <netdb.h>
150 #include <sys/socket.h>
151
152 #ifndef __BEOS__
153 #include <netinet/tcp.h>
154 #ifndef __OS2__
155 #include <arpa/inet.h>
156 #endif
157 #else
158 #include <socket.h>
159 #endif
160
161 #if defined(__EMX__) || defined (__OS2__)
162 #include <sys/select.h>  /* OS/2/EMX needs a little help with select */
163 #include <nerrno.h>
164 #endif
165
166 #endif
167
168 #include "project.h"
169 #include "jbsockets.h"
170 #include "filters.h"
171 #include "errlog.h"
172
173 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
174
175
176 /*********************************************************************
177  *
178  * Function    :  connect_to
179  *
180  * Description :  Open a socket and connect to it.  Will check
181  *                that this is allowed according to ACL.
182  *
183  * Parameters  :
184  *          1  :  host = hostname to connect to
185  *          2  :  portnum = port to connent on
186  *          3  :  csp = Current client state (buffers, headers, etc...)
187  *                      Not modified, only used for source IP and ACL.
188  *
189  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
190  *                file descriptor.
191  *
192  *********************************************************************/
193 jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
194 {
195    struct sockaddr_in inaddr;
196    jb_socket fd;
197    int addr;
198    fd_set wfds;
199    struct timeval tv[1];
200 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
201    int   flags;
202 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
203
204 #ifdef FEATURE_ACL
205    struct access_control_addr dst[1];
206 #endif /* def FEATURE_ACL */
207
208    memset((char *)&inaddr, 0, sizeof inaddr);
209
210    if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
211    {
212       csp->http->host_ip_addr_str = strdup("unknown");
213       return(JB_INVALID_SOCKET);
214    }
215
216 #ifdef FEATURE_ACL
217    dst->addr = ntohl((unsigned long) addr);
218    dst->port = portnum;
219
220    if (block_acl(dst, csp))
221    {
222 #ifdef __OS2__
223       errno = SOCEPERM;
224 #else
225       errno = EPERM;
226 #endif
227       return(JB_INVALID_SOCKET);
228    }
229 #endif /* def FEATURE_ACL */
230
231    inaddr.sin_addr.s_addr = addr;
232    inaddr.sin_family      = AF_INET;
233    csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
234
235 #ifndef _WIN32
236    if (sizeof(inaddr.sin_port) == sizeof(short))
237 #endif /* ndef _WIN32 */
238    {
239       inaddr.sin_port = htons((unsigned short) portnum);
240    }
241 #ifndef _WIN32
242    else
243    {
244       inaddr.sin_port = htonl((unsigned long)portnum);
245    }
246 #endif /* ndef _WIN32 */
247
248 #ifdef _WIN32
249    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
250 #else
251    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
252 #endif
253    {
254       return(JB_INVALID_SOCKET);
255    }
256
257 #ifdef TCP_NODELAY
258    {  /* turn off TCP coalescence */
259       int mi = 1;
260       setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
261    }
262 #endif /* def TCP_NODELAY */
263
264 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
265    if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
266    {
267       flags |= O_NDELAY;
268       fcntl(fd, F_SETFL, flags);
269    }
270 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
271
272    while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
273    {
274 #ifdef _WIN32
275       if (errno == WSAEINPROGRESS)
276 #elif __OS2__ 
277       if (sock_errno() == EINPROGRESS)
278 #else /* ifndef _WIN32 */
279       if (errno == EINPROGRESS)
280 #endif /* ndef _WIN32 || __OS2__ */
281       {
282          break;
283       }
284
285 #ifdef __OS2__ 
286       if (sock_errno() != EINTR)
287 #else
288       if (errno != EINTR)
289 #endif /* __OS2__ */
290       {
291          close_socket(fd);
292          return(JB_INVALID_SOCKET);
293       }
294    }
295
296 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
297    if (flags != -1)
298    {
299       flags &= ~O_NDELAY;
300       fcntl(fd, F_SETFL, flags);
301    }
302 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
303
304    /* wait for connection to complete */
305    FD_ZERO(&wfds);
306    FD_SET(fd, &wfds);
307
308    tv->tv_sec  = 30;
309    tv->tv_usec = 0;
310
311    /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
312    if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
313    {
314       close_socket(fd);
315       return(JB_INVALID_SOCKET);
316    }
317    return(fd);
318
319 }
320
321
322 /*********************************************************************
323  *
324  * Function    :  write_socket
325  *
326  * Description :  Write the contents of buf (for n bytes) to socket fd.
327  *
328  * Parameters  :
329  *          1  :  fd = file descriptor (aka. handle) of socket to write to.
330  *          2  :  buf = pointer to data to be written.
331  *          3  :  len = length of data to be written to the socket "fd".
332  *
333  * Returns     :  0 on success (entire buffer sent).
334  *                nonzero on error.
335  *
336  *********************************************************************/
337 int write_socket(jb_socket fd, const char *buf, int len)
338 {
339    if (len == 0)
340    {
341       return 0;
342    }
343
344    if (len < 0)
345    {
346       return 1;
347    }
348
349    log_error(LOG_LEVEL_LOG, "%N", len, buf);
350
351 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA)
352    return (send(fd, buf, len, 0) != len);
353 #elif defined(__OS2__)
354    /*
355     * Break the data up into SOCKET_SEND_MAX chunks for sending...
356     * OS/2 seemed to complain when the chunks were too large.
357     */
358 #define SOCKET_SEND_MAX 65000
359    {
360       int write_len = 0, send_len, send_rc = 0, i = 0;
361       while ((i < len) && (send_rc != -1))
362       {
363          if ((i + SOCKET_SEND_MAX) > len)
364             send_len = len - i;
365          else
366             send_len = SOCKET_SEND_MAX;
367          send_rc = send(fd,(char*)buf + i, send_len, 0);
368          if (send_rc == -1)
369             return 1;
370          i = i + send_len;
371       }
372       return 0;
373    }
374 #else
375    return (write(fd, buf, len) != len);
376 #endif
377
378 }
379
380
381 /*********************************************************************
382  *
383  * Function    :  read_socket
384  *
385  * Description :  Read from a TCP/IP socket in a platform independent way.
386  *
387  * Parameters  :
388  *          1  :  fd = file descriptor of the socket to read
389  *          2  :  buf = pointer to buffer where data will be written
390  *                Must be >= len bytes long.
391  *          3  :  len = maximum number of bytes to read
392  *
393  * Returns     :  On success, the number of bytes read is returned (zero
394  *                indicates end of file), and the file position is advanced
395  *                by this number.  It is not an error if this number is
396  *                smaller than the number of bytes requested; this may hap-
397  *                pen for example because fewer bytes are actually available
398  *                right now (maybe because we were close to end-of-file, or
399  *                because we are reading from a pipe, or from a terminal,
400  *                or because read() was interrupted by a signal).  On error,
401  *                -1 is returned, and errno is set appropriately.  In this
402  *                case it is left unspecified whether the file position (if
403  *                any) changes.
404  *
405  *********************************************************************/
406 int read_socket(jb_socket fd, char *buf, int len)
407 {
408    if (len <= 0)
409    {
410       return(0);
411    }
412
413 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA) || defined(__OS2__)
414    return(recv(fd, buf, len, 0));
415 #else
416    return(read(fd, buf, len));
417 #endif
418 }
419
420
421 /*********************************************************************
422  *
423  * Function    :  close_socket
424  *
425  * Description :  Closes a TCP/IP socket
426  *
427  * Parameters  :
428  *          1  :  fd = file descriptor of socket to be closed
429  *
430  * Returns     :  void
431  *
432  *********************************************************************/
433 void close_socket(jb_socket fd)
434 {
435 #if defined(_WIN32) || defined(__BEOS__)
436    closesocket(fd);
437 #elif defined(AMIGA)
438    CloseSocket(fd); 
439 #elif defined(__OS2__)
440    soclose(fd);
441 #else
442    close(fd);
443 #endif
444
445 }
446
447
448 /*********************************************************************
449  *
450  * Function    :  bind_port
451  *
452  * Description :  Call socket, set socket options, and listen.
453  *                Called by listen_loop to "boot up" our proxy address.
454  *
455  * Parameters  :
456  *          1  :  hostnam = TCP/IP address to bind/listen to
457  *          2  :  portnum = port to listen on
458  *          3  :  pfd = pointer used to return file descriptor.
459  *
460  * Returns     :  if success, returns 0 and sets *pfd.
461  *                if failure, returns -3 if address is in use,
462  *                                    -2 if address unresolvable,
463  *                                    -1 otherwise
464  *********************************************************************/
465 int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
466 {
467    struct sockaddr_in inaddr;
468    jb_socket fd;
469 #ifndef _WIN32
470    int one = 1;
471 #endif /* ndef _WIN32 */
472
473    *pfd = JB_INVALID_SOCKET;
474
475    memset((char *)&inaddr, '\0', sizeof inaddr);
476
477    inaddr.sin_family      = AF_INET;
478    inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
479
480    if (inaddr.sin_addr.s_addr == INADDR_NONE)
481    {
482       return(-2);
483    }
484
485 #ifndef _WIN32
486    if (sizeof(inaddr.sin_port) == sizeof(short))
487 #endif /* ndef _WIN32 */
488    {
489       inaddr.sin_port = htons((unsigned short) portnum);
490    }
491 #ifndef _WIN32
492    else
493    {
494       inaddr.sin_port = htonl((unsigned long) portnum);
495    }
496 #endif /* ndef _WIN32 */
497
498    fd = socket(AF_INET, SOCK_STREAM, 0);
499
500 #ifdef _WIN32
501    if (fd == JB_INVALID_SOCKET)
502 #else
503    if (fd < 0)
504 #endif
505    {
506       return(-1);
507    }
508
509 #ifndef _WIN32
510    /*
511     * This is not needed for Win32 - in fact, it stops
512     * duplicate instances of JunkBuster from being caught.
513     *
514     * On UNIX, we assume the user is sensible enough not
515     * to start JunkBuster multiple times on the same IP.
516     * Without this, stopping and restarting JunkBuster
517     * from a script fails.
518     * Note: SO_REUSEADDR is meant to only take over
519     * sockets which are *not* in listen state in Linux,
520     * e.g. sockets in TIME_WAIT. YMMV.
521     */
522    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
523 #endif /* ndef _WIN32 */
524
525    if (bind (fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
526    {
527       close_socket (fd);
528 #ifdef _WIN32
529       if (errno == WSAEADDRINUSE)
530 #else
531       if (errno == EADDRINUSE)
532 #endif
533       {
534          return(-3);
535       }
536       else
537       {
538          return(-1);
539       }
540    }
541
542    while (listen(fd, 5) == -1)
543    {
544       if (errno != EINTR)
545       {
546          return(-1);
547       }
548    }
549
550    *pfd = fd;
551    return 0;
552
553 }
554
555
556 /*********************************************************************
557  *
558  * Function    :  accept_connection
559  *
560  * Description :  Accepts a connection on a socket.  Socket must have
561  *                been created using bind_port().
562  *
563  * Parameters  :
564  *          1  :  csp = Client state, cfd, ip_addr_str, and 
565  *                ip_addr_long will be set by this routine.
566  *          2  :  fd  = file descriptor returned from bind_port
567  *
568  * Returns     :  when a connection is accepted, it returns 1 (TRUE).
569  *                On an error it returns 0 (FALSE).
570  *
571  *********************************************************************/
572 int accept_connection(struct client_state * csp, jb_socket fd)
573 {
574    struct sockaddr_in client, server;
575    struct hostent *host = NULL;
576    jb_socket afd;
577    size_t c_length, s_length;
578 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
579    struct hostent result;
580 #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
581    struct hostent_data hdata;
582 #else
583    char hbuf[HOSTENT_BUFFER_SIZE];
584    int thd_err;
585 #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
586 #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
587
588    c_length = s_length = sizeof(client);
589
590 #ifdef _WIN32
591    afd = accept (fd, (struct sockaddr *) &client, &c_length);
592    if (afd == JB_INVALID_SOCKET)
593    {
594       return 0;
595    }
596 #else
597    do
598    {
599       afd = accept (fd, (struct sockaddr *) &client, &c_length);
600    } while (afd < 1 && errno == EINTR);
601    if (afd < 0)
602    {
603       return 0;
604    }
605 #endif
606
607    /* 
608     * Determine the IP-Adress that the client used to reach us
609     * and the hostname associated with that address
610     */
611    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
612    {
613       csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
614 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
615       gethostbyaddr_r((const char *)&server.sin_addr,
616                       sizeof(server.sin_addr), AF_INET,
617                       &result, hbuf, HOSTENT_BUFFER_SIZE,
618                       &host, &thd_err);
619 #elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
620       host = gethostbyaddr_r((const char *)&server.sin_addr,
621                       sizeof(server.sin_addr), AF_INET,
622                       &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
623 #elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
624       if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
625                                sizeof(server.sin_addr), AF_INET,
626                                &result, &hdata))
627       {
628          host = &result;
629       }
630       else
631       {
632          host = NULL;
633       }
634 #else
635       host = gethostbyaddr((const char *)&server.sin_addr, 
636                            sizeof(server.sin_addr), AF_INET);
637 #endif
638       if (host == NULL)
639       {
640          log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
641       }
642       else
643       {
644          csp->my_hostname = strdup(host->h_name);
645       }
646    }
647
648    csp->cfd    = afd;
649    csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
650    csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
651
652    return 1;
653
654 }
655
656
657 /*********************************************************************
658  *
659  * Function    :  resolve_hostname_to_ip
660  *
661  * Description :  Resolve a hostname to an internet tcp/ip address.
662  *                NULL or an empty string resolve to INADDR_ANY.
663  *
664  * Parameters  :
665  *          1  :  host = hostname to resolve
666  *
667  * Returns     :  INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
668  *
669  *********************************************************************/
670 unsigned long resolve_hostname_to_ip(const char *host)
671 {
672    struct sockaddr_in inaddr;
673    struct hostent *hostp;
674 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
675    struct hostent result;
676 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
677    char hbuf[HOSTENT_BUFFER_SIZE];
678    int thd_err;
679 #else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
680    struct hostent_data hdata;
681 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
682 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
683
684    if ((host == NULL) || (*host == '\0'))
685    {
686       return(INADDR_ANY);
687    }
688
689    memset((char *) &inaddr, 0, sizeof inaddr);
690
691    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
692    {
693 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
694       gethostbyname_r(host, &result, hbuf,
695                       HOSTENT_BUFFER_SIZE, &hostp, &thd_err);
696 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
697       hostp = gethostbyname_r(host, &result, hbuf,
698                       HOSTENT_BUFFER_SIZE, &thd_err);
699 #elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
700       if (0 == gethostbyname_r(host, &result, &hdata))
701       {
702          hostp = &result;
703       }
704       else
705       {
706          hostp = NULL;
707       }
708 #else
709       hostp = gethostbyname(host);
710 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
711       if (hostp == NULL)
712       {
713          errno = EINVAL;
714          log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
715          return(INADDR_NONE);
716       }
717       if (hostp->h_addrtype != AF_INET)
718       {
719 #ifdef _WIN32
720          errno = WSAEPROTOTYPE;
721 #else
722          errno = EPROTOTYPE;
723 #endif 
724          log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
725          return(INADDR_NONE);
726       }
727       memcpy(
728          (char *) &inaddr.sin_addr,
729          (char *) hostp->h_addr,
730          sizeof(inaddr.sin_addr)
731       );
732    }
733    return(inaddr.sin_addr.s_addr);
734
735 }
736
737
738 /*
739   Local Variables:
740   tab-width: 3
741   end:
742 */