76f1cb8c878e487e7443ddb408511b5789a158ce
[privoxy.git] / jbsockets.c
1 const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.50 2008/12/20 14:53:55 fabiankeil 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-2007 the SourceForge
12  *                Privoxy team. http://www.privoxy.org/
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.50  2008/12/20 14:53:55  fabiankeil
39  *    Add config option socket-timeout to control the time
40  *    Privoxy waits for data to arrive on a socket. Useful
41  *    in case of stale ssh tunnels or when fuzz-testing.
42  *
43  *    Revision 1.49  2008/11/10 17:03:57  fabiankeil
44  *    Fix a gcc44 warning and remove a now-obsolete cast.
45  *
46  *    Revision 1.48  2008/09/04 08:13:58  fabiankeil
47  *    Prepare for critical sections on Windows by adding a
48  *    layer of indirection before the pthread mutex functions.
49  *
50  *    Revision 1.47  2008/03/26 18:07:07  fabiankeil
51  *    Add hostname directive. Closes PR#1918189.
52  *
53  *    Revision 1.46  2008/03/21 11:13:57  fabiankeil
54  *    Only gather host information if it's actually needed.
55  *    Also move the code out of accept_connection() so it's less likely
56  *    to delay other incoming connections if the host is misconfigured.
57  *
58  *    Revision 1.45  2007/09/30 16:59:22  fabiankeil
59  *    Set the maximum listen() backlog to 128. Apparently SOMAXCONN is
60  *    neither high enough, nor a hard limit on mingw32. Again for BR#1795281.
61  *
62  *    Revision 1.44  2007/09/15 13:01:31  fabiankeil
63  *    Increase listen() backlog to SOMAXCONN (or 128) to decrease
64  *    chances of dropped connections under load. Problem reported
65  *    and fix suggested by nobody in BR#1795281.
66  *
67  *    Revision 1.43  2007/06/01 18:16:36  fabiankeil
68  *    Use the same mutex for gethostbyname() and gethostbyaddr() to prevent
69  *    deadlocks and crashes on OpenBSD and possibly other OS with neither
70  *    gethostbyname_r() nor gethostaddr_r(). Closes BR#1729174.
71  *    Thanks to Ralf Horstmann for report and solution.
72  *
73  *    Revision 1.42  2007/04/01 17:37:07  fabiankeil
74  *    - Add DNS retries for Solaris and other systems
75  *      whose gethostbyname_r version takes five arguments.
76  *    - Move maximum number of DNS retries into a macro.
77  *
78  *    Revision 1.41  2006/11/13 19:05:51  fabiankeil
79  *    Make pthread mutex locking more generic. Instead of
80  *    checking for OSX and OpenBSD, check for FEATURE_PTHREAD
81  *    and use mutex locking unless there is an _r function
82  *    available. Better safe than sorry.
83  *
84  *    Fixes "./configure --disable-pthread" and should result
85  *    in less threading-related problems on pthread-using platforms,
86  *    but it still doesn't fix BR#1122404.
87  *
88  *    Revision 1.40  2006/09/02 15:36:42  fabiankeil
89  *    Follow the OpenBSD port's lead and protect the resolve
90  *    functions on OpenBSD as well.
91  *
92  *    Revision 1.39  2006/08/03 02:46:41  david__schmidt
93  *    Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
94  *
95  *    Revision 1.38  2006/07/18 14:48:46  david__schmidt
96  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
97  *    with what was really the latest development (the v_3_0_branch branch)
98  *
99  *    Revision 1.35.2.8  2006/01/21 16:16:08  david__schmidt
100  *    Thanks to  Edward Carrel for his patch to modernize OSX's\rpthreads support.  See bug #1409623.
101  *
102  *    Revision 1.35.2.7  2005/05/07 21:50:55  david__schmidt
103  *    A few memory leaks plugged (mostly on error paths)
104  *
105  *    Revision 1.35.2.6  2003/12/17 16:34:40  oes
106  *    Cosmetics
107  *
108  *    Revision 1.35.2.5  2003/04/29 11:32:54  oes
109  *    Don't rely on h_addr being non-NULL after gethostbyname.
110  *    Works around an oddness in Max OSX and closes bug #724796
111  *
112  *    Revision 1.35.2.4  2003/04/04 12:40:20  oes
113  *    Made sure the errno set by bind, not close[socket] is used in
114  *    bind_port. Probably fixes bugs #713777, #705562.
115  *
116  *    Revision 1.35.2.3  2003/03/07 03:41:04  david__schmidt
117  *    Wrapping all *_r functions (the non-_r versions of them) with mutex semaphores for OSX.  Hopefully this will take care of all of those pesky crash reports.
118  *
119  *    Revision 1.35.2.2  2002/11/20 14:37:24  oes
120  *    Fixed Win32 error logging in bind_port.
121  *    Thanks to Oliver Stoeneberg for the hint.
122  *
123  *    Revision 1.35.2.1  2002/05/26 23:41:27  joergs
124  *    AmigaOS: Fixed wrong type of len in write_socket()
125  *
126  *    Revision 1.35  2002/04/26 15:50:04  joergs
127  *    AmigaOS: No socklen_t, added AMIGA to the systems using int instead.
128  *
129  *    Revision 1.34  2002/04/08 20:31:41  swa
130  *    fixed JB spelling
131  *
132  *    Revision 1.33  2002/04/03 16:02:18  gliptak
133  *    Correcting compile warning with older gcc
134  *
135  *    Revision 1.32  2002/03/31 17:18:59  jongfoster
136  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
137  *
138  *    Revision 1.31  2002/03/29 03:33:13  david__schmidt
139  *    Fix Mac OSX compiler warnings
140  *
141  *    Revision 1.30  2002/03/27 14:32:43  david__schmidt
142  *    More compiler warning message maintenance
143  *
144  *    Revision 1.29  2002/03/26 22:29:54  swa
145  *    we have a new homepage!
146  *
147  *    Revision 1.28  2002/03/24 13:25:43  swa
148  *    name change related issues
149  *
150  *    Revision 1.27  2002/03/13 00:27:05  jongfoster
151  *    Killing warnings
152  *
153  *    Revision 1.26  2002/03/11 22:07:02  david__schmidt
154  *    OS/2 port maintenance:
155  *    - Fixed EMX build - it had decayed a little
156  *    - Fixed inexplicable crash during FD_ZERO - must be due to a bad macro.
157  *      substituted a memset for now.
158  *
159  *    Revision 1.25  2002/03/09 20:03:52  jongfoster
160  *    - Making various functions return int rather than size_t.
161  *      (Undoing a recent change).  Since size_t is unsigned on
162  *      Windows, functions like read_socket that return -1 on
163  *      error cannot return a size_t.
164  *
165  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
166  *      crashes, and also frequently caused JB to jump to 100%
167  *      CPU and stay there.  (Because it thought it had just
168  *      read ((unsigned)-1) == 4Gb of data...)
169  *
170  *    - The signature of write_socket has changed, it now simply
171  *      returns success=0/failure=nonzero.
172  *
173  *    - Trying to get rid of a few warnings --with-debug on
174  *      Windows, I've introduced a new type "jb_socket".  This is
175  *      used for the socket file descriptors.  On Windows, this
176  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
177  *      an int.  The error value can't be -1 any more, so it's
178  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
179  *      Windows it maps to the #define INVALID_SOCKET.)
180  *
181  *    - The signature of bind_port has changed.
182  *
183  *    Revision 1.24  2002/03/07 03:51:36  oes
184  *     - Improved handling of failed DNS lookups
185  *     - Fixed compiler warnings etc
186  *
187  *    Revision 1.23  2002/03/05 00:36:01  jongfoster
188  *    Fixing bug 514988 - unable to restart Junkbuster
189  *
190  *    Revision 1.22  2002/03/04 02:08:02  david__schmidt
191  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
192  *
193  *    Revision 1.21  2002/01/09 14:32:33  oes
194  *    Added support for gethostbyname_r and gethostbyaddr_r.
195  *
196  *    Revision 1.20  2001/11/16 00:48:48  jongfoster
197  *    Enabling duplicate-socket detection for all platforms, not
198  *    just Win32.
199  *
200  *    Revision 1.19  2001/10/25 03:40:47  david__schmidt
201  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
202  *    threads to call select() simultaneously.  So, it's time to do a real, live,
203  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
204  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
205  *
206  *    Revision 1.18  2001/09/21 23:02:02  david__schmidt
207  *    Cleaning up 2 compiler warnings on OS/2.
208  *
209  *    Revision 1.17  2001/09/13 20:11:46  jongfoster
210  *    Fixing 2 compiler warnings under Win32
211  *
212  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
213  *    Tidying up #defines:
214  *    - All feature #defines are now of the form FEATURE_xxx
215  *    - Permanently turned off WIN_GUI_EDIT
216  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
217  *
218  *    Revision 1.15  2001/07/29 17:40:43  jongfoster
219  *    Fixed compiler warning by adding a cast
220  *
221  *    Revision 1.14  2001/07/18 13:47:59  oes
222  *    Eliminated dirty hack for getsockbyname()
223  *
224  *    Revision 1.13  2001/07/15 13:56:57  jongfoster
225  *    Removing unused local variable.
226  *
227  *    Revision 1.12  2001/07/01 17:04:11  oes
228  *    Bugfix: accept_connection no longer uses the obsolete hstrerror() function
229  *
230  *    Revision 1.11  2001/06/29 21:45:41  oes
231  *    Indentation, CRLF->LF, Tab-> Space
232  *
233  *    Revision 1.10  2001/06/29 13:29:15  oes
234  *    - Added remote (server) host IP to csp->http->host_ip_addr_str
235  *    - Added detection of local socket IP and fqdn
236  *    - Removed logentry from cancelled commit
237  *
238  *    Revision 1.9  2001/06/07 23:06:09  jongfoster
239  *    The host parameter to connect_to() is now const.
240  *
241  *    Revision 1.8  2001/06/03 19:12:07  oes
242  *    filled comment
243  *
244  *    Revision 1.7  2001/05/28 16:14:00  jongfoster
245  *    Fixing bug in LOG_LEVEL_LOG
246  *
247  *    Revision 1.6  2001/05/26 17:28:32  jongfoster
248  *    Fixed LOG_LEVEL_LOG
249  *
250  *    Revision 1.5  2001/05/26 15:26:15  jongfoster
251  *    ACL feature now provides more security by immediately dropping
252  *    connections from untrusted hosts.
253  *
254  *    Revision 1.4  2001/05/26 00:37:42  jongfoster
255  *    Cosmetic indentation correction.
256  *
257  *    Revision 1.3  2001/05/25 21:57:54  jongfoster
258  *    Now gives a warning under Windows if you try to bind
259  *    it to a port that's already in use.
260  *
261  *    Revision 1.2  2001/05/17 23:01:01  oes
262  *     - Cleaned CRLF's from the sources and related files
263  *
264  *    Revision 1.1.1.1  2001/05/15 13:58:54  oes
265  *    Initial import of version 2.9.3 source tree
266  *
267  *
268  *********************************************************************/
269 \f
270
271 #include "config.h"
272
273 #include <stdlib.h>
274 #include <stdio.h>
275 #include <string.h>
276 #include <errno.h>
277 #include <fcntl.h>
278 #include <sys/types.h>
279
280 #ifdef _WIN32
281
282 #ifndef STRICT
283 #define STRICT
284 #endif
285 #include <windows.h>
286 #include <sys/timeb.h>
287 #include <io.h>
288
289 #else
290
291 #ifndef __OS2__
292 #include <unistd.h>
293 #endif
294 #include <sys/time.h>
295 #include <netinet/in.h>
296 #include <sys/ioctl.h>
297 #include <netdb.h>
298 #include <sys/socket.h>
299
300 #ifndef __BEOS__
301 #include <netinet/tcp.h>
302 #ifndef __OS2__
303 #include <arpa/inet.h>
304 #endif
305 #else
306 #include <socket.h>
307 #endif
308
309 #if defined(__EMX__) || defined (__OS2__)
310 #include <sys/select.h>  /* OS/2/EMX needs a little help with select */
311 #ifdef __OS2__
312 #include <nerrno.h>
313 #endif
314 #endif
315
316 #endif
317
318 #include "project.h"
319
320 #ifdef FEATURE_PTHREAD
321 #include "jcc.h"
322 /* jcc.h is for mutex semaphores only */
323 #endif /* def FEATURE_PTHREAD */
324
325 #include "jbsockets.h"
326 #include "filters.h"
327 #include "errlog.h"
328
329 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
330
331 /*
332  * Maximum number of gethostbyname(_r) retries in case of
333  * soft errors (TRY_AGAIN).
334  * XXX: Does it make sense to make this a config option?
335  */
336 #define MAX_DNS_RETRIES 10
337
338 #define MAX_LISTEN_BACKLOG 128
339
340
341 /*********************************************************************
342  *
343  * Function    :  connect_to
344  *
345  * Description :  Open a socket and connect to it.  Will check
346  *                that this is allowed according to ACL.
347  *
348  * Parameters  :
349  *          1  :  host = hostname to connect to
350  *          2  :  portnum = port to connent on (XXX: should be unsigned)
351  *          3  :  csp = Current client state (buffers, headers, etc...)
352  *                      Not modified, only used for source IP and ACL.
353  *
354  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
355  *                file descriptor.
356  *
357  *********************************************************************/
358 #ifdef HAVE_GETADDRINFO
359 /* Getaddrinfo implementation */
360 jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
361 {
362    struct addrinfo hints, *result, *rp;
363    char service[6];
364    int retval;
365    jb_socket fd;
366    fd_set wfds;
367    struct timeval tv[1];
368 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
369    int   flags;
370 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
371    int connect_failed;
372
373 #ifdef FEATURE_ACL
374    struct access_control_addr dst[1];
375 #endif /* def FEATURE_ACL */
376
377    retval = snprintf(service, sizeof(service), "%d", portnum);
378    if (-1 == retval || sizeof(service) <= retval)
379    {
380       log_error(LOG_LEVEL_ERROR,
381             "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
382             portnum);
383       csp->http->host_ip_addr_str = strdup("unknown");
384       return(JB_INVALID_SOCKET);
385    }
386
387    memset((char *)&hints, 0, sizeof hints);
388    hints.ai_family = AF_UNSPEC;
389    hints.ai_socktype = SOCK_STREAM;
390    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; /* avoid service look-up */
391    if ((retval = getaddrinfo(host, service, &hints, &result)))
392    {
393       log_error(LOG_LEVEL_INFO,
394             "Can not resolve %s: %s", host, gai_strerror(retval));
395       csp->http->host_ip_addr_str = strdup("unknown");
396       return(JB_INVALID_SOCKET);
397    }
398
399    for (rp = result; rp != NULL; rp = rp->ai_next)
400    {
401
402 #ifdef FEATURE_ACL
403       memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
404
405       if (block_acl(dst, csp))
406       {
407 #ifdef __OS2__
408          errno = SOCEPERM;
409 #else
410          errno = EPERM;
411 #endif
412          continue;
413       }
414 #endif /* def FEATURE_ACL */
415
416       csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
417       retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
418             csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
419       if (!csp->http->host_ip_addr_str || retval)
420       {
421          log_error(LOG_LEVEL_ERROR, "Can not save csp->http->host_ip_addr_str: %s",
422                (csp->http->host_ip_addr_str) ? gai_strerror(retval) :
423                "Insufficient memory");
424          freez(csp->http->host_ip_addr_str);
425          continue;
426       }
427
428 #ifdef _WIN32
429       if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) ==
430             JB_INVALID_SOCKET)
431 #else
432       if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
433 #endif
434       {
435          continue;
436       }
437
438 #ifdef TCP_NODELAY
439       {  /* turn off TCP coalescence */
440          int mi = 1;
441          setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
442       }
443 #endif /* def TCP_NODELAY */
444
445 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
446       if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
447       {
448          flags |= O_NDELAY;
449          fcntl(fd, F_SETFL, flags);
450       }
451 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
452
453       connect_failed = 0;
454       while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
455       {
456 #ifdef _WIN32
457          if (errno == WSAEINPROGRESS)
458 #elif __OS2__ 
459          if (sock_errno() == EINPROGRESS)
460 #else /* ifndef _WIN32 */
461          if (errno == EINPROGRESS)
462 #endif /* ndef _WIN32 || __OS2__ */
463          {
464             break;
465          }
466
467 #ifdef __OS2__ 
468          if (sock_errno() != EINTR)
469 #else
470          if (errno != EINTR)
471 #endif /* __OS2__ */
472          {
473             close_socket(fd);
474             connect_failed = 1;
475             break;
476          }
477       }
478       if (connect_failed)
479       {
480          continue;
481       }
482
483 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
484       if (flags != -1)
485       {
486          flags &= ~O_NDELAY;
487          fcntl(fd, F_SETFL, flags);
488       }
489 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
490
491       /* wait for connection to complete */
492       FD_ZERO(&wfds);
493       FD_SET(fd, &wfds);
494
495       tv->tv_sec  = 30;
496       tv->tv_usec = 0;
497
498       /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
499       if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
500       {
501          close_socket(fd);
502          continue;
503       }
504       
505       break; /* for; Connection established; don't try other addresses */
506    }
507
508    freeaddrinfo(result);
509    if (!rp)
510    {
511       log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s", host, service);
512       return(JB_INVALID_SOCKET);
513    }
514    /* XXX: Current connection verification (EINPROGRESS && select() for
515     * writing) is not sufficient. E.g. on my Linux-2.6.27 with glibc-2.6
516     * select returns socket ready for writing, however subsequential write(2)
517     * fails with ENOCONNECT. Read Linux connect(2) man page about non-blocking
518     * sockets.
519     * Thus we can not log here the socket is connected. */
520    /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/
521
522    return(fd);
523
524 }
525
526 # else /* ndef HAVE_GETADDRINFO */
527 /* Pre-getaddrinfo implementation */
528
529 jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
530 {
531    struct sockaddr_in inaddr;
532    jb_socket fd;
533    unsigned int addr;
534    fd_set wfds;
535    struct timeval tv[1];
536 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
537    int   flags;
538 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
539
540 #ifdef FEATURE_ACL
541    struct access_control_addr dst[1];
542 #endif /* def FEATURE_ACL */
543
544    memset((char *)&inaddr, 0, sizeof inaddr);
545
546    if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
547    {
548       csp->http->host_ip_addr_str = strdup("unknown");
549       return(JB_INVALID_SOCKET);
550    }
551
552 #ifdef FEATURE_ACL
553    dst->addr = ntohl(addr);
554    dst->port = portnum;
555
556    if (block_acl(dst, csp))
557    {
558 #ifdef __OS2__
559       errno = SOCEPERM;
560 #else
561       errno = EPERM;
562 #endif
563       return(JB_INVALID_SOCKET);
564    }
565 #endif /* def FEATURE_ACL */
566
567    inaddr.sin_addr.s_addr = addr;
568    inaddr.sin_family      = AF_INET;
569    csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
570
571 #ifndef _WIN32
572    if (sizeof(inaddr.sin_port) == sizeof(short))
573 #endif /* ndef _WIN32 */
574    {
575       inaddr.sin_port = htons((unsigned short) portnum);
576    }
577 #ifndef _WIN32
578    else
579    {
580       inaddr.sin_port = htonl((unsigned long)portnum);
581    }
582 #endif /* ndef _WIN32 */
583
584 #ifdef _WIN32
585    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
586 #else
587    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
588 #endif
589    {
590       return(JB_INVALID_SOCKET);
591    }
592
593 #ifdef TCP_NODELAY
594    {  /* turn off TCP coalescence */
595       int mi = 1;
596       setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
597    }
598 #endif /* def TCP_NODELAY */
599
600 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
601    if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
602    {
603       flags |= O_NDELAY;
604       fcntl(fd, F_SETFL, flags);
605    }
606 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
607
608    while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
609    {
610 #ifdef _WIN32
611       if (errno == WSAEINPROGRESS)
612 #elif __OS2__ 
613       if (sock_errno() == EINPROGRESS)
614 #else /* ifndef _WIN32 */
615       if (errno == EINPROGRESS)
616 #endif /* ndef _WIN32 || __OS2__ */
617       {
618          break;
619       }
620
621 #ifdef __OS2__ 
622       if (sock_errno() != EINTR)
623 #else
624       if (errno != EINTR)
625 #endif /* __OS2__ */
626       {
627          close_socket(fd);
628          return(JB_INVALID_SOCKET);
629       }
630    }
631
632 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
633    if (flags != -1)
634    {
635       flags &= ~O_NDELAY;
636       fcntl(fd, F_SETFL, flags);
637    }
638 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
639
640    /* wait for connection to complete */
641    FD_ZERO(&wfds);
642    FD_SET(fd, &wfds);
643
644    tv->tv_sec  = 30;
645    tv->tv_usec = 0;
646
647    /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
648    if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
649    {
650       close_socket(fd);
651       return(JB_INVALID_SOCKET);
652    }
653    return(fd);
654
655 }
656 #endif /* ndef HAVE_GETADDRINFO */
657
658
659 /*********************************************************************
660  *
661  * Function    :  write_socket
662  *
663  * Description :  Write the contents of buf (for n bytes) to socket fd.
664  *
665  * Parameters  :
666  *          1  :  fd = file descriptor (aka. handle) of socket to write to.
667  *          2  :  buf = pointer to data to be written.
668  *          3  :  len = length of data to be written to the socket "fd".
669  *
670  * Returns     :  0 on success (entire buffer sent).
671  *                nonzero on error.
672  *
673  *********************************************************************/
674 #ifdef AMIGA
675 int write_socket(jb_socket fd, const char *buf, ssize_t len)
676 #else
677 int write_socket(jb_socket fd, const char *buf, size_t len)
678 #endif
679 {
680    if (len == 0)
681    {
682       return 0;
683    }
684
685    if (len < 0) /* constant condition - size_t isn't ever negative */ 
686    {
687       return 1;
688    }
689
690    log_error(LOG_LEVEL_LOG, "%N", len, buf);
691
692 #if defined(_WIN32)
693    return (send(fd, buf, (int)len, 0) != (int)len);
694 #elif defined(__BEOS__) || defined(AMIGA)
695    return (send(fd, buf, len, 0) != len);
696 #elif defined(__OS2__)
697    /*
698     * Break the data up into SOCKET_SEND_MAX chunks for sending...
699     * OS/2 seemed to complain when the chunks were too large.
700     */
701 #define SOCKET_SEND_MAX 65000
702    {
703       int write_len = 0, send_len, send_rc = 0, i = 0;
704       while ((i < len) && (send_rc != -1))
705       {
706          if ((i + SOCKET_SEND_MAX) > len)
707             send_len = len - i;
708          else
709             send_len = SOCKET_SEND_MAX;
710          send_rc = send(fd,(char*)buf + i, send_len, 0);
711          if (send_rc == -1)
712             return 1;
713          i = i + send_len;
714       }
715       return 0;
716    }
717 #else
718    return (write(fd, buf, len) != len);
719 #endif
720
721 }
722
723
724 /*********************************************************************
725  *
726  * Function    :  read_socket
727  *
728  * Description :  Read from a TCP/IP socket in a platform independent way.
729  *
730  * Parameters  :
731  *          1  :  fd = file descriptor of the socket to read
732  *          2  :  buf = pointer to buffer where data will be written
733  *                Must be >= len bytes long.
734  *          3  :  len = maximum number of bytes to read
735  *
736  * Returns     :  On success, the number of bytes read is returned (zero
737  *                indicates end of file), and the file position is advanced
738  *                by this number.  It is not an error if this number is
739  *                smaller than the number of bytes requested; this may hap-
740  *                pen for example because fewer bytes are actually available
741  *                right now (maybe because we were close to end-of-file, or
742  *                because we are reading from a pipe, or from a terminal,
743  *                or because read() was interrupted by a signal).  On error,
744  *                -1 is returned, and errno is set appropriately.  In this
745  *                case it is left unspecified whether the file position (if
746  *                any) changes.
747  *
748  *********************************************************************/
749 int read_socket(jb_socket fd, char *buf, int len)
750 {
751    if (len <= 0)
752    {
753       return(0);
754    }
755
756 #if defined(_WIN32)
757    return(recv(fd, buf, len, 0));
758 #elif defined(__BEOS__) || defined(AMIGA) || defined(__OS2__)
759    return(recv(fd, buf, (size_t)len, 0));
760 #else
761    return(read(fd, buf, (size_t)len));
762 #endif
763 }
764
765
766 /*********************************************************************
767  *
768  * Function    :  data_is_available
769  *
770  * Description :  Waits for data to arrive on a socket.
771  *
772  * Parameters  :
773  *          1  :  fd = file descriptor of the socket to read
774  *          2  :  seconds_to_wait = number of seconds after which we give up.
775  *
776  * Returns     :  TRUE if data arrived in time,
777  *                FALSE otherwise.
778  *
779  *********************************************************************/
780 int data_is_available(jb_socket fd, int seconds_to_wait)
781 {
782    fd_set rfds;
783    struct timeval timeout;
784    int n;
785
786    memset(&timeout, 0, sizeof(timeout));
787    timeout.tv_sec = seconds_to_wait;
788
789 #ifdef __OS2__
790    /* Copy and pasted from jcc.c ... */
791    memset(&rfds, 0, sizeof(fd_set));
792 #else
793    FD_ZERO(&rfds);
794 #endif
795    FD_SET(fd, &rfds);
796
797    n = select(fd+1, &rfds, NULL, NULL, &timeout);
798
799    /*
800     * XXX: Do we care about the different error conditions?
801     */
802    return (n == 1);
803 }
804
805
806 /*********************************************************************
807  *
808  * Function    :  close_socket
809  *
810  * Description :  Closes a TCP/IP socket
811  *
812  * Parameters  :
813  *          1  :  fd = file descriptor of socket to be closed
814  *
815  * Returns     :  void
816  *
817  *********************************************************************/
818 void close_socket(jb_socket fd)
819 {
820 #if defined(_WIN32) || defined(__BEOS__)
821    closesocket(fd);
822 #elif defined(AMIGA)
823    CloseSocket(fd); 
824 #elif defined(__OS2__)
825    soclose(fd);
826 #else
827    close(fd);
828 #endif
829
830 }
831
832
833 /*********************************************************************
834  *
835  * Function    :  bind_port
836  *
837  * Description :  Call socket, set socket options, and listen.
838  *                Called by listen_loop to "boot up" our proxy address.
839  *
840  * Parameters  :
841  *          1  :  hostnam = TCP/IP address to bind/listen to
842  *          2  :  portnum = port to listen on
843  *          3  :  pfd = pointer used to return file descriptor.
844  *
845  * Returns     :  if success, returns 0 and sets *pfd.
846  *                if failure, returns -3 if address is in use,
847  *                                    -2 if address unresolvable,
848  *                                    -1 otherwise
849  *********************************************************************/
850 int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
851 {
852 #ifdef HAVE_GETADDRINFO
853    struct addrinfo hints;
854    struct addrinfo *result, *rp;
855    /* TODO: portnum shuld be string to allow symbolic service names in
856     * configuration and to avoid following int2string */
857    char servnam[6];
858    int retval;
859 #else
860    struct sockaddr_in inaddr;
861 #endif /* def HAVE_GETADDRINFO */
862    jb_socket fd;
863 #ifndef _WIN32
864    int one = 1;
865 #endif /* ndef _WIN32 */
866
867    *pfd = JB_INVALID_SOCKET;
868
869 #ifdef HAVE_GETADDRINFO
870    retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
871    if (-1 == retval || sizeof(servnam) <= retval)
872    {
873       log_error(LOG_LEVEL_ERROR,
874             "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
875             portnum);
876       return -1;
877    }
878
879    memset(&hints, 0, sizeof(struct addrinfo));
880    hints.ai_family=AF_UNSPEC;
881    hints.ai_socktype=SOCK_STREAM;
882    hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG;
883    hints.ai_protocol=0; /* Realy any stream protocol or TCP only */
884    hints.ai_canonname=NULL;
885    hints.ai_addr=NULL;
886    hints.ai_next=NULL;
887
888    if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
889    {
890       log_error(LOG_LEVEL_ERROR,
891             "Can not resolve %s: %s", hostnam, gai_strerror(retval));
892       return -2;
893    }
894 #else
895    memset((char *)&inaddr, '\0', sizeof inaddr);
896
897    inaddr.sin_family      = AF_INET;
898    inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
899
900    if (inaddr.sin_addr.s_addr == INADDR_NONE)
901    {
902       return(-2);
903    }
904
905 #ifndef _WIN32
906    if (sizeof(inaddr.sin_port) == sizeof(short))
907 #endif /* ndef _WIN32 */
908    {
909       inaddr.sin_port = htons((unsigned short) portnum);
910    }
911 #ifndef _WIN32
912    else
913    {
914       inaddr.sin_port = htonl((unsigned long) portnum);
915    }
916 #endif /* ndef _WIN32 */
917 #endif /* def HAVE_GETADDRINFO */
918
919 #ifdef HAVE_GETADDRINFO
920    for (rp = result; rp != NULL; rp = rp->ai_next)
921    {
922       fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
923 #else
924    fd = socket(AF_INET, SOCK_STREAM, 0);
925 #endif /* def HAVE_GETADDRINFO */
926
927 #ifdef _WIN32
928    if (fd == JB_INVALID_SOCKET)
929 #else
930    if (fd < 0)
931 #endif
932    {
933 #ifdef HAVE_GETADDRINFO
934       continue;
935 #else
936       return(-1);
937 #endif
938    }
939
940 #ifndef _WIN32
941    /*
942     * This is not needed for Win32 - in fact, it stops
943     * duplicate instances of Privoxy from being caught.
944     *
945     * On UNIX, we assume the user is sensible enough not
946     * to start Privoxy multiple times on the same IP.
947     * Without this, stopping and restarting Privoxy
948     * from a script fails.
949     * Note: SO_REUSEADDR is meant to only take over
950     * sockets which are *not* in listen state in Linux,
951     * e.g. sockets in TIME_WAIT. YMMV.
952     */
953    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
954 #endif /* ndef _WIN32 */
955
956 #ifdef HAVE_GETADDRINFO
957    if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
958 #else
959    if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
960 #endif
961    {
962 #ifdef _WIN32
963       errno = WSAGetLastError();
964       if (errno == WSAEADDRINUSE)
965 #else
966       if (errno == EADDRINUSE)
967 #endif
968       {
969 #ifdef HAVE_GETADDRINFO
970          freeaddrinfo(result);
971 #endif
972          close_socket(fd);
973          return(-3);
974       }
975       else
976       {
977          close_socket(fd);
978 #ifndef HAVE_GETADDRINFO
979          return(-1);
980       }
981    }
982 #else
983       }
984    }
985    else
986       /* bind() succeeded, escape from for-loop */
987       /* TODO: Support multiple listening sockets (e.g. localhost resolves to
988        * AF_INET and AF_INET6, but only fist address is used */
989       break;
990    }
991
992    freeaddrinfo(result);
993    if (rp == NULL)
994    {
995       /* All bind()s failed */
996       return(-1);
997    }
998 #endif /* ndef HAVE_GETADDRINFO */
999
1000    while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
1001    {
1002       if (errno != EINTR)
1003       {
1004          return(-1);
1005       }
1006    }
1007
1008    *pfd = fd;
1009    return 0;
1010
1011 }
1012
1013
1014 /*********************************************************************
1015  *
1016  * Function    :  get_host_information
1017  *
1018  * Description :  Determines the IP address the client used to
1019  *                reach us and the hostname associated with it.
1020  *
1021  *                XXX: Most of the code has been copy and pasted
1022  *                from accept_connection() and not all of the
1023  *                ifdefs paths have been tested afterwards.
1024  *
1025  * Parameters  :
1026  *          1  :  afd = File descriptor returned from accept().
1027  *          2  :  ip_address = Pointer to return the pointer to
1028  *                             the ip address string.
1029  *          3  :  hostname =   Pointer to return the pointer to
1030  *                             the hostname or NULL if the caller
1031  *                             isn't interested in it.
1032  *
1033  * Returns     :  void.
1034  *
1035  *********************************************************************/
1036 void get_host_information(jb_socket afd, char **ip_address, char **hostname)
1037 {
1038 #ifdef HAVE_GETNAMEINFO
1039    struct sockaddr_storage server;
1040    int retval;
1041 #else
1042    struct sockaddr_in server;
1043    struct hostent *host = NULL;
1044 #endif /* HAVE_GETNAMEINFO */
1045 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1046    /* according to accept_connection() this fixes a warning. */
1047    int s_length, s_length_provided;
1048 #else
1049    socklen_t s_length, s_length_provided;
1050 #endif
1051 #ifndef HAVE_GETNAMEINFO
1052 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1053    struct hostent result;
1054 #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1055    struct hostent_data hdata;
1056 #else
1057    char hbuf[HOSTENT_BUFFER_SIZE];
1058    int thd_err;
1059 #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1060 #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1061 #endif /* ifndef HAVE_GETNAMEINFO */
1062    s_length = s_length_provided = sizeof(server);
1063
1064    if (NULL != hostname)
1065    {
1066       *hostname = NULL;
1067    }
1068    *ip_address = NULL;
1069
1070    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1071    {
1072       if (s_length > s_length_provided)
1073       {
1074          log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
1075          return;
1076       }
1077 #ifdef HAVE_GETNAMEINFO
1078       *ip_address = malloc(NI_MAXHOST);
1079       if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
1080                   *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) {
1081          log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s",
1082                gai_strerror(retval));
1083          freez(*ip_address);
1084          return;
1085       }
1086 #else
1087       *ip_address = strdup(inet_ntoa(server.sin_addr));
1088 #endif /* HAVE_GETNAMEINFO */
1089       if (NULL == hostname)
1090       {
1091          /*
1092           * We're done here, the caller isn't
1093           * interested in knowing the hostname.
1094           */
1095          return;
1096       }
1097
1098 #ifdef HAVE_GETNAMEINFO
1099       *hostname = malloc(NI_MAXHOST);
1100       if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
1101                   *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) {
1102          log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s",
1103                gai_strerror(retval));
1104          freez(*hostname);
1105       }
1106 #else
1107 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1108       gethostbyaddr_r((const char *)&server.sin_addr,
1109                       sizeof(server.sin_addr), AF_INET,
1110                       &result, hbuf, HOSTENT_BUFFER_SIZE,
1111                       &host, &thd_err);
1112 #elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1113       host = gethostbyaddr_r((const char *)&server.sin_addr,
1114                       sizeof(server.sin_addr), AF_INET,
1115                       &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1116 #elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1117       if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1118                                sizeof(server.sin_addr), AF_INET,
1119                                &result, &hdata))
1120       {
1121          host = &result;
1122       }
1123       else
1124       {
1125          host = NULL;
1126       }
1127 #elif FEATURE_PTHREAD
1128       privoxy_mutex_lock(&resolver_mutex);
1129       host = gethostbyaddr((const char *)&server.sin_addr, 
1130                            sizeof(server.sin_addr), AF_INET);
1131       privoxy_mutex_unlock(&resolver_mutex);
1132 #else
1133       host = gethostbyaddr((const char *)&server.sin_addr, 
1134                            sizeof(server.sin_addr), AF_INET);
1135 #endif
1136       if (host == NULL)
1137       {
1138          log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1139       }
1140       else
1141       {
1142          *hostname = strdup(host->h_name);
1143       }
1144 #endif /* else def HAVE_GETNAMEINFO */
1145    }
1146
1147    return;
1148 }
1149
1150
1151 /*********************************************************************
1152  *
1153  * Function    :  accept_connection
1154  *
1155  * Description :  Accepts a connection on a socket.  Socket must have
1156  *                been created using bind_port().
1157  *
1158  * Parameters  :
1159  *          1  :  csp = Client state, cfd, ip_addr_str, and 
1160  *                ip_addr_long will be set by this routine.
1161  *          2  :  fd  = file descriptor returned from bind_port
1162  *
1163  * Returns     :  when a connection is accepted, it returns 1 (TRUE).
1164  *                On an error it returns 0 (FALSE).
1165  *
1166  *********************************************************************/
1167 int accept_connection(struct client_state * csp, jb_socket fd)
1168 {
1169 #ifdef HAVE_GETNAMEINFO
1170    /* XXX: client is stored directly into csp->tcp_addr */
1171 #define client (csp->tcp_addr)
1172    int retval;
1173 #else
1174    struct sockaddr_in client;
1175 #endif
1176    jb_socket afd;
1177 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1178    /* Wierdness - fix a warning. */
1179    int c_length;
1180 #else
1181    socklen_t c_length;
1182 #endif
1183
1184    c_length = sizeof(client);
1185
1186 #ifdef _WIN32
1187    afd = accept (fd, (struct sockaddr *) &client, &c_length);
1188    if (afd == JB_INVALID_SOCKET)
1189    {
1190       return 0;
1191    }
1192 #else
1193    do
1194    {
1195       afd = accept (fd, (struct sockaddr *) &client, &c_length);
1196    } while (afd < 1 && errno == EINTR);
1197    if (afd < 0)
1198    {
1199       return 0;
1200    }
1201 #endif
1202
1203    csp->cfd = afd;
1204 #ifdef HAVE_GETNAMEINFO
1205    csp->ip_addr_str = malloc(NI_MAXHOST);
1206    retval = getnameinfo((struct sockaddr *) &client, c_length,
1207          csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1208    if (!csp->ip_addr_str || retval)
1209    {
1210       log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s",
1211             (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory");
1212       freez(csp->ip_addr_str);
1213    }
1214 #undef client
1215 #else
1216    csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
1217    csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1218 #endif /* def HAVE_GETNAMEINFO */
1219
1220    return 1;
1221
1222 }
1223
1224
1225 /*********************************************************************
1226  *
1227  * Function    :  resolve_hostname_to_ip
1228  *
1229  * Description :  Resolve a hostname to an internet tcp/ip address.
1230  *                NULL or an empty string resolve to INADDR_ANY.
1231  *
1232  * Parameters  :
1233  *          1  :  host = hostname to resolve
1234  *
1235  * Returns     :  INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
1236  *
1237  *********************************************************************/
1238 unsigned long resolve_hostname_to_ip(const char *host)
1239 {
1240    struct sockaddr_in inaddr;
1241    struct hostent *hostp;
1242    unsigned int dns_retries = 0;
1243 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1244    struct hostent result;
1245 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1246    char hbuf[HOSTENT_BUFFER_SIZE];
1247    int thd_err;
1248 #else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1249    struct hostent_data hdata;
1250 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1251 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1252
1253    if ((host == NULL) || (*host == '\0'))
1254    {
1255       return(INADDR_ANY);
1256    }
1257
1258    memset((char *) &inaddr, 0, sizeof inaddr);
1259
1260    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
1261    {
1262 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
1263       while (gethostbyname_r(host, &result, hbuf,
1264                 HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
1265              && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1266       {   
1267          log_error(LOG_LEVEL_ERROR,
1268             "Timeout #%u while trying to resolve %s. Trying again.",
1269             dns_retries, host);
1270       }
1271 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1272       while (NULL == (hostp = gethostbyname_r(host, &result,
1273                                  hbuf, HOSTENT_BUFFER_SIZE, &thd_err))
1274              && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1275       {   
1276          log_error(LOG_LEVEL_ERROR,
1277             "Timeout #%u while trying to resolve %s. Trying again.",
1278             dns_retries, host);
1279       }
1280 #elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1281       /*
1282        * XXX: Doesn't retry in case of soft errors.
1283        * Does this gethostbyname_r version set h_errno?
1284        */
1285       if (0 == gethostbyname_r(host, &result, &hdata))
1286       {
1287          hostp = &result;
1288       }
1289       else
1290       {
1291          hostp = NULL;
1292       }
1293 #elif FEATURE_PTHREAD
1294       privoxy_mutex_lock(&resolver_mutex);
1295       while (NULL == (hostp = gethostbyname(host))
1296              && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1297       {   
1298          log_error(LOG_LEVEL_ERROR,
1299             "Timeout #%u while trying to resolve %s. Trying again.",
1300             dns_retries, host);
1301       }
1302       privoxy_mutex_unlock(&resolver_mutex);
1303 #else
1304       while (NULL == (hostp = gethostbyname(host))
1305              && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1306       {
1307          log_error(LOG_LEVEL_ERROR,
1308             "Timeout #%u while trying to resolve %s. Trying again.",
1309             dns_retries, host);
1310       }
1311 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1312       /*
1313        * On Mac OSX, if a domain exists but doesn't have a type A
1314        * record associated with it, the h_addr member of the struct
1315        * hostent returned by gethostbyname is NULL, even if h_length
1316        * is 4. Therefore the second test below.
1317        */
1318       if (hostp == NULL || hostp->h_addr == NULL)
1319       {
1320          errno = EINVAL;
1321          log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
1322          return(INADDR_NONE);
1323       }
1324       if (hostp->h_addrtype != AF_INET)
1325       {
1326 #ifdef _WIN32
1327          errno = WSAEPROTOTYPE;
1328 #else
1329          errno = EPROTOTYPE;
1330 #endif 
1331          log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
1332          return(INADDR_NONE);
1333       }
1334       memcpy(
1335          (char *) &inaddr.sin_addr,
1336          (char *) hostp->h_addr,
1337          sizeof(inaddr.sin_addr)
1338       );
1339    }
1340    return(inaddr.sin_addr.s_addr);
1341
1342 }
1343
1344
1345 /*
1346   Local Variables:
1347   tab-width: 3
1348   end:
1349
1350   vim:softtabstop=3 shiftwidth=3
1351 */