Update a link to the libcurl mailinglist archive
[privoxy.git] / jbsockets.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
4  *
5  * Purpose     :  Contains wrappers for system-specific sockets code,
6  *                so that the rest of Privoxy can be more
7  *                OS-independent.  Contains #ifdefs to make this work
8  *                on many platforms.
9  *
10  * Copyright   :  Written by and Copyright (C) 2001-2017 the
11  *                Privoxy team. https://www.privoxy.org/
12  *
13  *                Based on the Internet Junkbuster originally written
14  *                by and Copyright (C) 1997 Anonymous Coders and
15  *                Junkbusters Corporation.  http://www.junkbusters.com
16  *
17  *                This program is free software; you can redistribute it
18  *                and/or modify it under the terms of the GNU General
19  *                Public License as published by the Free Software
20  *                Foundation; either version 2 of the License, or (at
21  *                your option) any later version.
22  *
23  *                This program is distributed in the hope that it will
24  *                be useful, but WITHOUT ANY WARRANTY; without even the
25  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
26  *                PARTICULAR PURPOSE.  See the GNU General Public
27  *                License for more details.
28  *
29  *                The GNU General Public License should be included with
30  *                this file.  If not, you can view it at
31  *                http://www.gnu.org/copyleft/gpl.html
32  *                or write to the Free Software Foundation, Inc., 59
33  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  *
35  *********************************************************************/
36
37
38 #include "config.h"
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <sys/types.h>
46
47 #ifdef _WIN32
48
49 #ifndef STRICT
50 #define STRICT
51 #endif
52 #include <winsock2.h>
53 #include <windows.h>
54 #include <sys/timeb.h>
55 #include <io.h>
56
57 #else
58
59 #include <unistd.h>
60 #include <sys/time.h>
61 #include <netinet/in.h>
62 #include <sys/ioctl.h>
63 #include <netdb.h>
64 #include <sys/socket.h>
65
66 #ifndef __BEOS__
67 #include <netinet/tcp.h>
68 #include <arpa/inet.h>
69 #else
70 #include <socket.h>
71 #endif
72
73 #endif
74
75 #ifdef HAVE_POLL
76 #ifdef __GLIBC__
77 #include <sys/poll.h>
78 #else
79 #include <poll.h>
80 #endif /* def __GLIBC__ */
81 #endif /* HAVE_POLL */
82
83 #include "project.h"
84
85 /* For mutex semaphores only */
86 #include "jcc.h"
87
88 #include "jbsockets.h"
89 #include "filters.h"
90 #include "errlog.h"
91 #include "miscutil.h"
92
93 /* Mac OSX doesn't define AI_NUMERICSESRV */
94 #ifndef AI_NUMERICSERV
95 #define AI_NUMERICSERV 0
96 #endif
97
98 /*
99  * Maximum number of gethostbyname(_r) retries in case of
100  * soft errors (TRY_AGAIN).
101  * XXX: Does it make sense to make this a config option?
102  */
103 #define MAX_DNS_RETRIES 10
104
105 #ifdef HAVE_RFC2553
106 static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp);
107 #else
108 static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp);
109 #endif
110
111 /*********************************************************************
112  *
113  * Function    :  set_no_delay_flag
114  *
115  * Description :  Disables the Nagle algorithm (TCP send coalescence)
116  *                for the given socket.
117  *
118  * Parameters  :
119  *          1  :  fd = The file descriptor to operate on
120  *
121  * Returns     :  void
122  *
123  *********************************************************************/
124 static void set_no_delay_flag(int fd)
125 {
126 #ifdef TCP_NODELAY
127    int mi = 1;
128
129    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &mi, sizeof(int)))
130    {
131       log_error(LOG_LEVEL_ERROR,
132          "Failed to disable TCP coalescence for socket %d", fd);
133    }
134 #else
135 #warning set_no_delay_flag() is a nop due to lack of TCP_NODELAY
136 #endif /* def TCP_NODELAY */
137 }
138
139 /*********************************************************************
140  *
141  * Function    :  connect_to
142  *
143  * Description :  Open a socket and connect to it.  Will check
144  *                that this is allowed according to ACL.
145  *
146  * Parameters  :
147  *          1  :  host = hostname to connect to
148  *          2  :  portnum = port to connect to (XXX: should be unsigned)
149  *          3  :  csp = Current client state (buffers, headers, etc...)
150  *
151  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
152  *                file descriptor.
153  *
154  *********************************************************************/
155 jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
156 {
157    jb_socket fd;
158    int forwarded_connect_retries = 0;
159
160    do
161    {
162       /*
163        * XXX: The whole errno overloading is ridiculous and should
164        *      be replaced with something sane and thread safe
165        */
166       /* errno = 0;*/
167 #ifdef HAVE_RFC2553
168       fd = rfc2553_connect_to(host, portnum, csp);
169 #else
170       fd = no_rfc2553_connect_to(host, portnum, csp);
171 #endif
172       if ((fd != JB_INVALID_SOCKET) || (errno == EINVAL)
173          || (csp->fwd == NULL)
174          || ((csp->fwd->forward_host == NULL) && (csp->fwd->type == SOCKS_NONE)))
175       {
176          break;
177       }
178       forwarded_connect_retries++;
179       if (csp->config->forwarded_connect_retries != 0)
180       {
181          log_error(LOG_LEVEL_ERROR,
182             "Attempt %d of %d to connect to %s failed. Trying again.",
183             forwarded_connect_retries, csp->config->forwarded_connect_retries + 1, host);
184       }
185
186    } while (forwarded_connect_retries < csp->config->forwarded_connect_retries);
187
188    return fd;
189 }
190
191 #ifdef HAVE_RFC2553
192 /* Getaddrinfo implementation */
193 static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp)
194 {
195    struct addrinfo hints, *result, *rp;
196    char service[6];
197    int retval;
198    jb_socket fd;
199    struct pollfd poll_fd[1];
200 #if !defined(_WIN32) && !defined(__BEOS__)
201    int   flags;
202 #endif
203    int connect_failed;
204    /*
205     * XXX: Initializing it here is only necessary
206     *      because not all situations are properly
207     *      covered yet.
208     */
209    int socket_error = 0;
210
211 #ifdef FEATURE_ACL
212    struct access_control_addr dst[1];
213 #endif /* def FEATURE_ACL */
214
215    /* Don't leak memory when retrying. */
216    freez(csp->error_message);
217    freez(csp->http->host_ip_addr_str);
218
219    retval = snprintf(service, sizeof(service), "%d", portnum);
220    if ((-1 == retval) || (sizeof(service) <= retval))
221    {
222       log_error(LOG_LEVEL_ERROR,
223          "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
224          portnum);
225       csp->error_message = strdup("Invalid port number");
226       csp->http->host_ip_addr_str = strdup("unknown");
227       return(JB_INVALID_SOCKET);
228    }
229
230    memset((char *)&hints, 0, sizeof(hints));
231    hints.ai_family = AF_UNSPEC;
232    hints.ai_socktype = SOCK_STREAM;
233    hints.ai_flags = AI_NUMERICSERV; /* avoid service look-up */
234 #ifdef AI_ADDRCONFIG
235    hints.ai_flags |= AI_ADDRCONFIG;
236 #endif
237    if ((retval = getaddrinfo(host, service, &hints, &result)))
238    {
239       log_error(LOG_LEVEL_INFO,
240          "Can not resolve %s: %s", host, gai_strerror(retval));
241       csp->error_message = strdup(gai_strerror(retval));
242       csp->http->host_ip_addr_str = strdup("unknown");
243       /* XXX: Should find a better way to propagate this error. */
244       errno = EINVAL;
245       return(JB_INVALID_SOCKET);
246    }
247
248    csp->http->host_ip_addr_str = malloc_or_die(NI_MAXHOST);
249
250    for (rp = result; rp != NULL; rp = rp->ai_next)
251    {
252
253 #ifdef FEATURE_ACL
254       memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
255
256       if (block_acl(dst, csp))
257       {
258          socket_error = errno = EPERM;
259          continue;
260       }
261 #endif /* def FEATURE_ACL */
262
263       retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
264          csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
265       if (retval)
266       {
267          log_error(LOG_LEVEL_ERROR,
268             "Failed to get the host name from the socket structure: %s",
269             gai_strerror(retval));
270          continue;
271       }
272
273       fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
274 #ifdef _WIN32
275       if (fd == JB_INVALID_SOCKET)
276 #else
277       if (fd < 0)
278 #endif
279       {
280          continue;
281       }
282
283 #ifdef FEATURE_EXTERNAL_FILTERS
284       mark_socket_for_close_on_execute(fd);
285 #endif
286
287       set_no_delay_flag(fd);
288
289 #if !defined(_WIN32) && !defined(__BEOS__)
290       if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
291       {
292          flags |= O_NDELAY;
293          fcntl(fd, F_SETFL, flags);
294       }
295 #endif /* !defined(_WIN32) && !defined(__BEOS__) */
296
297       connect_failed = 0;
298       while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
299       {
300 #ifdef _WIN32
301          if (errno == WSAEINPROGRESS)
302 #else /* ifndef _WIN32 */
303          if (errno == EINPROGRESS)
304 #endif /* ndef _WIN32 */
305          {
306             break;
307          }
308
309          if (errno != EINTR)
310          {
311             socket_error = errno;
312             close_socket(fd);
313             connect_failed = 1;
314             break;
315          }
316       }
317       if (connect_failed)
318       {
319          continue;
320       }
321
322 #if !defined(_WIN32) && !defined(__BEOS__)
323       if (flags != -1)
324       {
325          flags &= ~O_NDELAY;
326          fcntl(fd, F_SETFL, flags);
327       }
328 #endif /* !defined(_WIN32) && !defined(__BEOS__) */
329
330       poll_fd[0].fd = fd;
331       poll_fd[0].events = POLLOUT;
332
333       retval = poll(poll_fd, 1, 30000);
334       if (retval == 0)
335       {
336          if (rp->ai_next != NULL)
337          {
338             /* Log this now as we'll try another address next */
339             log_error(LOG_LEVEL_CONNECT,
340                "Could not connect to [%s]:%s: Operation timed out.",
341                csp->http->host_ip_addr_str, service);
342          }
343          else
344          {
345             /*
346              * This is the last address, don't log this now
347              * as it would result in a duplicated log message.
348              */
349             socket_error = ETIMEDOUT;
350          }
351       }
352       else if (retval > 0)
353       {
354          socklen_t optlen = sizeof(socket_error);
355          if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &optlen))
356          {
357             if (!socket_error)
358             {
359                /* Connection established, no need to try other addresses. */
360                break;
361             }
362             if (rp->ai_next != NULL)
363             {
364                /*
365                 * There's another address we can try, so log that this
366                 * one didn't work out. If the last one fails, too,
367                 * it will get logged outside the loop body so we don't
368                 * have to mention it here.
369                 */
370                log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.",
371                   csp->http->host_ip_addr_str, service, strerror(socket_error));
372             }
373          }
374          else
375          {
376             socket_error = errno;
377             log_error(LOG_LEVEL_ERROR, "Could not get the state of "
378                "the connection to [%s]:%s: %s; dropping connection.",
379                csp->http->host_ip_addr_str, service, strerror(errno));
380          }
381       }
382
383       /* Connection failed, try next address */
384       close_socket(fd);
385    }
386
387    freeaddrinfo(result);
388    if (!rp)
389    {
390       log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.",
391          host, service, strerror(socket_error));
392       csp->error_message = strdup(strerror(socket_error));
393       return(JB_INVALID_SOCKET);
394    }
395    log_error(LOG_LEVEL_CONNECT, "Connected to %s[%s]:%s.",
396       host, csp->http->host_ip_addr_str, service);
397
398    return(fd);
399
400 }
401
402 #else /* ndef HAVE_RFC2553 */
403 /* Pre-getaddrinfo implementation */
404
405 static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp)
406 {
407    struct sockaddr_in inaddr;
408    jb_socket fd;
409    unsigned int addr;
410    struct pollfd poll_fd[1];
411 #if !defined(_WIN32) && !defined(__BEOS__)
412    int   flags;
413 #endif
414
415 #ifdef FEATURE_ACL
416    struct access_control_addr dst[1];
417 #endif /* def FEATURE_ACL */
418
419    /* Don't leak memory when retrying. */
420    freez(csp->http->host_ip_addr_str);
421
422    memset((char *)&inaddr, 0, sizeof inaddr);
423
424    if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
425    {
426       csp->http->host_ip_addr_str = strdup("unknown");
427       return(JB_INVALID_SOCKET);
428    }
429
430 #ifdef FEATURE_ACL
431    dst->addr = ntohl(addr);
432    dst->port = portnum;
433
434    if (block_acl(dst, csp))
435    {
436       errno = EPERM;
437       return(JB_INVALID_SOCKET);
438    }
439 #endif /* def FEATURE_ACL */
440
441    inaddr.sin_addr.s_addr = addr;
442    inaddr.sin_family      = AF_INET;
443    csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
444
445 #ifndef _WIN32
446    if (sizeof(inaddr.sin_port) == sizeof(short))
447 #endif /* ndef _WIN32 */
448    {
449       inaddr.sin_port = htons((unsigned short) portnum);
450    }
451 #ifndef _WIN32
452    else
453    {
454       inaddr.sin_port = htonl((unsigned long)portnum);
455    }
456 #endif /* ndef _WIN32 */
457
458    fd = socket(inaddr.sin_family, SOCK_STREAM, 0);
459 #ifdef _WIN32
460    if (fd == JB_INVALID_SOCKET)
461 #else
462    if (fd < 0)
463 #endif
464    {
465       return(JB_INVALID_SOCKET);
466    }
467
468    set_no_delay_flag(fd);
469
470 #if !defined(_WIN32) && !defined(__BEOS__)
471    if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
472    {
473       flags |= O_NDELAY;
474       fcntl(fd, F_SETFL, flags);
475 #ifdef FEATURE_EXTERNAL_FILTERS
476       mark_socket_for_close_on_execute(fd);
477 #endif
478    }
479 #endif /* !defined(_WIN32) && !defined(__BEOS__) */
480
481    while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
482    {
483 #ifdef _WIN32
484       if (errno == WSAEINPROGRESS)
485 #else /* ifndef _WIN32 */
486       if (errno == EINPROGRESS)
487 #endif /* ndef _WIN32 */
488       {
489          break;
490       }
491
492       if (errno != EINTR)
493       {
494          close_socket(fd);
495          return(JB_INVALID_SOCKET);
496       }
497    }
498
499 #if !defined(_WIN32) && !defined(__BEOS__)
500    if (flags != -1)
501    {
502       flags &= ~O_NDELAY;
503       fcntl(fd, F_SETFL, flags);
504    }
505 #endif /* !defined(_WIN32) && !defined(__BEOS__) */
506
507    poll_fd[0].fd = fd;
508    poll_fd[0].events = POLLOUT;
509
510    if (poll(poll_fd, 1, 30000) <= 0)
511    {
512       close_socket(fd);
513       return(JB_INVALID_SOCKET);
514    }
515    return(fd);
516
517 }
518 #endif /* ndef HAVE_RFC2553 */
519
520
521 /*********************************************************************
522  *
523  * Function    :  write_socket
524  *
525  * Description :  Write the contents of buf (for n bytes) to socket fd.
526  *
527  * Parameters  :
528  *          1  :  fd = file descriptor (aka. handle) of socket to write to.
529  *          2  :  buf = pointer to data to be written.
530  *          3  :  len = length of data to be written to the socket "fd".
531  *
532  * Returns     :  0 on success (entire buffer sent).
533  *                nonzero on error.
534  *
535  *********************************************************************/
536 int write_socket(jb_socket fd, const char *buf, size_t len)
537 {
538    if (len == 0)
539    {
540       return 0;
541    }
542
543 #ifdef FUZZ
544    if (!daemon_mode && fd <= 3)
545    {
546       log_error(LOG_LEVEL_WRITING, "Pretending to write to socket %d: %N", fd, len, buf);
547       return 0;
548    }
549 #endif
550
551    log_error(LOG_LEVEL_WRITING, "to socket %d: %N", fd, len, buf);
552
553 #if defined(_WIN32)
554    return (send(fd, buf, (int)len, 0) != (int)len);
555 #elif defined(__BEOS__)
556    return (send(fd, buf, len, 0) != len);
557 #else
558    return (write(fd, buf, len) != len);
559 #endif
560
561 }
562
563
564 /*********************************************************************
565  *
566  * Function    :  write_socket_delayed
567  *
568  * Description :  Write the contents of buf (for n bytes) to
569  *                socket fd, optionally delaying the operation.
570  *
571  * Parameters  :
572  *          1  :  fd = File descriptor (aka. handle) of socket to write to.
573  *          2  :  buf = Pointer to data to be written.
574  *          3  :  len = Length of data to be written to the socket "fd".
575  *          4  :  delay = Delay in milliseconds.
576  *
577  * Returns     :  0 on success (entire buffer sent).
578  *                nonzero on error.
579  *
580  *********************************************************************/
581 int write_socket_delayed(jb_socket fd, const char *buf, size_t len, unsigned int delay)
582 {
583    size_t i = 0;
584
585    if (delay == 0)
586    {
587       return write_socket(fd, buf, len);
588    }
589
590    while (i < len)
591    {
592       size_t write_length;
593       enum {MAX_WRITE_LENGTH = 10};
594
595       if ((i + MAX_WRITE_LENGTH) > len)
596       {
597          write_length = len - i;
598       }
599       else
600       {
601          write_length = MAX_WRITE_LENGTH;
602       }
603
604       privoxy_millisleep(delay);
605
606       if (write_socket(fd, buf + i, write_length) != 0)
607       {
608          return 1;
609       }
610       i += write_length;
611    }
612
613    return 0;
614
615 }
616
617
618 /*********************************************************************
619  *
620  * Function    :  read_socket
621  *
622  * Description :  Read from a TCP/IP socket in a platform independent way.
623  *
624  * Parameters  :
625  *          1  :  fd = file descriptor of the socket to read
626  *          2  :  buf = pointer to buffer where data will be written
627  *                Must be >= len bytes long.
628  *          3  :  len = maximum number of bytes to read
629  *
630  * Returns     :  On success, the number of bytes read is returned (zero
631  *                indicates end of file), and the file position is advanced
632  *                by this number.  It is not an error if this number is
633  *                smaller than the number of bytes requested; this may hap-
634  *                pen for example because fewer bytes are actually available
635  *                right now (maybe because we were close to end-of-file, or
636  *                because we are reading from a pipe, or from a terminal,
637  *                or because read() was interrupted by a signal).  On error,
638  *                -1 is returned, and errno is set appropriately.  In this
639  *                case it is left unspecified whether the file position (if
640  *                any) changes.
641  *
642  *********************************************************************/
643 int read_socket(jb_socket fd, char *buf, int len)
644 {
645    int ret;
646
647    if (len <= 0)
648    {
649       return(0);
650    }
651
652 #if defined(_WIN32)
653    ret = recv(fd, buf, len, 0);
654 #elif defined(__BEOS__)
655    ret = recv(fd, buf, (size_t)len, 0);
656 #else
657    ret = (int)read(fd, buf, (size_t)len);
658 #endif
659
660    if (ret > 0)
661    {
662       log_error(LOG_LEVEL_RECEIVED, "from socket %d: %N", fd, ret, buf);
663    }
664
665    return ret;
666 }
667
668
669 /*********************************************************************
670  *
671  * Function    :  data_is_available
672  *
673  * Description :  Waits for data to arrive on a socket.
674  *
675  * Parameters  :
676  *          1  :  fd = file descriptor of the socket to read
677  *          2  :  seconds_to_wait = number of seconds after which we give up.
678  *
679  * Returns     :  TRUE if data arrived in time,
680  *                FALSE otherwise.
681  *
682  *********************************************************************/
683 int data_is_available(jb_socket fd, int seconds_to_wait)
684 {
685    int n;
686    char buf[10];
687    struct pollfd poll_fd[1];
688
689    poll_fd[0].fd = fd;
690    poll_fd[0].events = POLLIN;
691
692    n = poll(poll_fd, 1, seconds_to_wait * 1000);
693
694    /*
695     * XXX: Do we care about the different error conditions?
696     */
697    return ((n == 1) && (1 == recv(fd, buf, 1, MSG_PEEK)));
698 }
699
700
701 /*********************************************************************
702  *
703  * Function    :  close_socket
704  *
705  * Description :  Closes a TCP/IP socket
706  *
707  * Parameters  :
708  *          1  :  fd = file descriptor of socket to be closed
709  *
710  * Returns     :  void
711  *
712  *********************************************************************/
713 void close_socket(jb_socket fd)
714 {
715 #if defined(_WIN32) || defined(__BEOS__)
716    closesocket(fd);
717 #else
718    close(fd);
719 #endif
720 }
721
722
723 /*********************************************************************
724  *
725  * Function    :  drain_and_close_socket
726  *
727  * Description :  Closes a TCP/IP socket after draining unread data
728  *
729  * Parameters  :
730  *          1  :  fd = file descriptor of the socket to be closed
731  *
732  * Returns     :  void
733  *
734  *********************************************************************/
735 void drain_and_close_socket(jb_socket fd)
736 {
737 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
738    if (socket_is_still_alive(fd))
739 #endif
740    {
741       int bytes_drained_total = 0;
742       int bytes_drained;
743
744 #ifdef HAVE_SHUTDOWN
745 /* Apparently Windows has shutdown() but not SHUT_WR. */
746 #ifndef SHUT_WR
747 #define SHUT_WR 1
748 #endif
749       if (0 != shutdown(fd, SHUT_WR))
750       {
751          log_error(LOG_LEVEL_CONNECT, "Failed to shutdown socket %d: %E", fd);
752       }
753 #endif
754 #define ARBITRARY_DRAIN_LIMIT 10000
755       do
756       {
757          char drainage[500];
758
759          if (!data_is_available(fd, 0))
760          {
761             /*
762              * If there is no data available right now, don't try
763              * to drain the socket as read_socket() could block.
764              */
765             break;
766          }
767
768          bytes_drained = read_socket(fd, drainage, sizeof(drainage));
769          if (bytes_drained < 0)
770          {
771             log_error(LOG_LEVEL_CONNECT, "Failed to drain socket %d: %E", fd);
772          }
773          else if (bytes_drained > 0)
774          {
775             bytes_drained_total += bytes_drained;
776             if (bytes_drained_total > ARBITRARY_DRAIN_LIMIT)
777             {
778                log_error(LOG_LEVEL_CONNECT, "Giving up draining socket %d", fd);
779                break;
780             }
781          }
782       } while (bytes_drained > 0);
783       if (bytes_drained_total != 0)
784       {
785          log_error(LOG_LEVEL_CONNECT,
786             "Drained %d bytes before closing socket %d", bytes_drained_total, fd);
787       }
788    }
789
790    close_socket(fd);
791
792 }
793
794
795 /*********************************************************************
796  *
797  * Function    :  bind_port
798  *
799  * Description :  Call socket, set socket options, and listen.
800  *                Called by listen_loop to "boot up" our proxy address.
801  *
802  * Parameters  :
803  *          1  :  hostnam = TCP/IP address to bind/listen to
804  *          2  :  portnum = port to listen on
805  *          3  :  backlog = Listen backlog
806  *          4  :  pfd = pointer used to return file descriptor.
807  *
808  * Returns     :  if success, returns 0 and sets *pfd.
809  *                if failure, returns -3 if address is in use,
810  *                                    -2 if address unresolvable,
811  *                                    -1 otherwise
812  *********************************************************************/
813 int bind_port(const char *hostnam, int portnum, int backlog, jb_socket *pfd)
814 {
815 #ifdef HAVE_RFC2553
816    struct addrinfo hints;
817    struct addrinfo *result, *rp;
818    /*
819     * XXX: portnum should be a string to allow symbolic service
820     * names in the configuration file and to avoid the following
821     * int2string.
822     */
823    char servnam[6];
824    int retval;
825 #else
826    struct sockaddr_in inaddr;
827 #endif /* def HAVE_RFC2553 */
828    jb_socket fd;
829 #ifndef _WIN32
830    int one = 1;
831 #endif /* ndef _WIN32 */
832
833    *pfd = JB_INVALID_SOCKET;
834
835 #ifdef HAVE_RFC2553
836    retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
837    if ((-1 == retval) || (sizeof(servnam) <= retval))
838    {
839       log_error(LOG_LEVEL_ERROR,
840          "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
841          portnum);
842       return -1;
843    }
844
845    memset(&hints, 0, sizeof(struct addrinfo));
846    if (hostnam == NULL)
847    {
848       /*
849        * XXX: This is a hack. The right thing to do
850        * would be to bind to both AF_INET and AF_INET6.
851        * This will also fail if there is no AF_INET
852        * version available.
853        */
854       hints.ai_family = AF_INET;
855    }
856    else
857    {
858       hints.ai_family = AF_UNSPEC;
859    }
860    hints.ai_socktype = SOCK_STREAM;
861    hints.ai_flags = AI_PASSIVE;
862    hints.ai_protocol = 0; /* Really any stream protocol or TCP only */
863    hints.ai_canonname = NULL;
864    hints.ai_addr = NULL;
865    hints.ai_next = NULL;
866
867    if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
868    {
869       log_error(LOG_LEVEL_ERROR,
870          "Can not resolve %s: %s", hostnam, gai_strerror(retval));
871       return -2;
872    }
873 #else
874    memset((char *)&inaddr, '\0', sizeof inaddr);
875
876    inaddr.sin_family      = AF_INET;
877    inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
878
879    if (inaddr.sin_addr.s_addr == INADDR_NONE)
880    {
881       return(-2);
882    }
883
884 #ifndef _WIN32
885    if (sizeof(inaddr.sin_port) == sizeof(short))
886 #endif /* ndef _WIN32 */
887    {
888       inaddr.sin_port = htons((unsigned short) portnum);
889    }
890 #ifndef _WIN32
891    else
892    {
893       inaddr.sin_port = htonl((unsigned long) portnum);
894    }
895 #endif /* ndef _WIN32 */
896 #endif /* def HAVE_RFC2553 */
897
898 #ifdef HAVE_RFC2553
899    for (rp = result; rp != NULL; rp = rp->ai_next)
900    {
901       fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
902 #else
903    fd = socket(AF_INET, SOCK_STREAM, 0);
904 #endif /* def HAVE_RFC2553 */
905
906 #ifdef _WIN32
907    if (fd == JB_INVALID_SOCKET)
908 #else
909    if (fd < 0)
910 #endif
911    {
912 #ifdef HAVE_RFC2553
913       continue;
914 #else
915       return(-1);
916 #endif
917    }
918
919 #ifdef FEATURE_EXTERNAL_FILTERS
920    mark_socket_for_close_on_execute(fd);
921 #endif
922
923 #ifndef _WIN32
924    /*
925     * This is not needed for Win32 - in fact, it stops
926     * duplicate instances of Privoxy from being caught.
927     *
928     * On UNIX, we assume the user is sensible enough not
929     * to start Privoxy multiple times on the same IP.
930     * Without this, stopping and restarting Privoxy
931     * from a script fails.
932     * Note: SO_REUSEADDR is meant to only take over
933     * sockets which are *not* in listen state in Linux,
934     * e.g. sockets in TIME_WAIT. YMMV.
935     */
936    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
937 #endif /* ndef _WIN32 */
938
939 #ifdef IP_FREEBIND
940    setsockopt(fd, IPPROTO_IP, IP_FREEBIND, (char *)&one, sizeof(one));
941 #endif
942
943 #ifdef HAVE_RFC2553
944    if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
945 #else
946    if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
947 #endif
948    {
949 #ifdef _WIN32
950       errno = WSAGetLastError();
951       if (errno == WSAEADDRINUSE)
952 #else
953       if (errno == EADDRINUSE)
954 #endif
955       {
956 #ifdef HAVE_RFC2553
957          freeaddrinfo(result);
958 #endif
959          close_socket(fd);
960          return(-3);
961       }
962       else
963       {
964          close_socket(fd);
965 #ifndef HAVE_RFC2553
966          return(-1);
967       }
968    }
969 #else
970       }
971    }
972    else
973    {
974       /* bind() succeeded, escape from for-loop */
975       /*
976        * XXX: Support multiple listening sockets (e.g. localhost
977        * resolves to AF_INET and AF_INET6, but only the first address
978        * is used
979        */
980       break;
981    }
982    }
983
984    freeaddrinfo(result);
985    if (rp == NULL)
986    {
987       /* All bind()s failed */
988       return(-1);
989    }
990 #endif /* ndef HAVE_RFC2553 */
991
992    while (listen(fd, backlog) == -1)
993    {
994       if (errno != EINTR)
995       {
996          close_socket(fd);
997          return(-1);
998       }
999    }
1000
1001    *pfd = fd;
1002    return 0;
1003
1004 }
1005
1006
1007 /*********************************************************************
1008  *
1009  * Function    :  get_host_information
1010  *
1011  * Description :  Determines the IP address the client used to
1012  *                reach us and the hostname associated with it.
1013  *
1014  *                XXX: Most of the code has been copy and pasted
1015  *                from accept_connection() and not all of the
1016  *                ifdefs paths have been tested afterwards.
1017  *
1018  * Parameters  :
1019  *          1  :  afd = File descriptor returned from accept().
1020  *          2  :  ip_address = Pointer to return the pointer to
1021  *                             the ip address string.
1022  *          3  :  port =       Pointer to return the pointer to
1023  *                             the TCP port string.
1024  *          4  :  hostname =   Pointer to return the pointer to
1025  *                             the hostname or NULL if the caller
1026  *                             isn't interested in it.
1027  *
1028  * Returns     :  void.
1029  *
1030  *********************************************************************/
1031 void get_host_information(jb_socket afd, char **ip_address, char **port,
1032                           char **hostname)
1033 {
1034 #ifdef HAVE_RFC2553
1035    struct sockaddr_storage server;
1036    int retval;
1037 #else
1038    struct sockaddr_in server;
1039    struct hostent *host = NULL;
1040 #endif /* HAVE_RFC2553 */
1041 #if defined(_WIN32)
1042    /* according to accept_connection() this fixes a warning. */
1043    int s_length, s_length_provided;
1044 #else
1045    socklen_t s_length, s_length_provided;
1046 #endif
1047 #ifndef HAVE_RFC2553
1048 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1049    struct hostent result;
1050 #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1051    struct hostent_data hdata;
1052 #else
1053    char hbuf[HOSTENT_BUFFER_SIZE];
1054    int thd_err;
1055 #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1056 #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1057 #endif /* ifndef HAVE_RFC2553 */
1058    s_length = s_length_provided = sizeof(server);
1059
1060    if (NULL != hostname)
1061    {
1062       *hostname = NULL;
1063    }
1064    *ip_address = NULL;
1065    *port = NULL;
1066
1067    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1068    {
1069       if (s_length > s_length_provided)
1070       {
1071          log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
1072          return;
1073       }
1074 /*
1075  * XXX: Workaround for missing header on Windows when
1076  *      configured with --disable-ipv6-support.
1077  *      The proper fix is to not use NI_MAXSERV in
1078  *      that case. It works by accident on other platforms
1079  *      as <netdb.h> is included unconditionally there.
1080  */
1081 #ifndef NI_MAXSERV
1082 #define NI_MAXSERV 32
1083 #endif
1084       *port = malloc_or_die(NI_MAXSERV);
1085
1086 #ifdef HAVE_RFC2553
1087       *ip_address = malloc_or_die(NI_MAXHOST);
1088       retval = getnameinfo((struct sockaddr *) &server, s_length,
1089          *ip_address, NI_MAXHOST, *port, NI_MAXSERV,
1090          NI_NUMERICHOST|NI_NUMERICSERV);
1091       if (retval)
1092       {
1093          log_error(LOG_LEVEL_ERROR,
1094             "Unable to print my own IP address: %s", gai_strerror(retval));
1095          freez(*ip_address);
1096          freez(*port);
1097          return;
1098       }
1099 #else
1100       *ip_address = strdup(inet_ntoa(server.sin_addr));
1101       snprintf(*port, NI_MAXSERV, "%hu", ntohs(server.sin_port));
1102 #endif /* HAVE_RFC2553 */
1103       if (NULL == hostname)
1104       {
1105          /*
1106           * We're done here, the caller isn't
1107           * interested in knowing the hostname.
1108           */
1109          return;
1110       }
1111
1112 #ifdef HAVE_RFC2553
1113       *hostname = malloc_or_die(NI_MAXHOST);
1114       retval = getnameinfo((struct sockaddr *) &server, s_length,
1115          *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
1116       if (retval)
1117       {
1118          log_error(LOG_LEVEL_ERROR,
1119             "Unable to resolve my own IP address: %s", gai_strerror(retval));
1120          freez(*hostname);
1121       }
1122 #else
1123 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1124       gethostbyaddr_r((const char *)&server.sin_addr,
1125                       sizeof(server.sin_addr), AF_INET,
1126                       &result, hbuf, HOSTENT_BUFFER_SIZE,
1127                       &host, &thd_err);
1128 #elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1129       host = gethostbyaddr_r((const char *)&server.sin_addr,
1130                       sizeof(server.sin_addr), AF_INET,
1131                       &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1132 #elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1133       if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1134                                sizeof(server.sin_addr), AF_INET,
1135                                &result, &hdata))
1136       {
1137          host = &result;
1138       }
1139       else
1140       {
1141          host = NULL;
1142       }
1143 #elif defined(MUTEX_LOCKS_AVAILABLE)
1144       privoxy_mutex_lock(&resolver_mutex);
1145       host = gethostbyaddr((const char *)&server.sin_addr,
1146                            sizeof(server.sin_addr), AF_INET);
1147       privoxy_mutex_unlock(&resolver_mutex);
1148 #else
1149       host = gethostbyaddr((const char *)&server.sin_addr,
1150                            sizeof(server.sin_addr), AF_INET);
1151 #endif
1152       if (host == NULL)
1153       {
1154          log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1155       }
1156       else
1157       {
1158          *hostname = strdup(host->h_name);
1159       }
1160 #endif /* else def HAVE_RFC2553 */
1161    }
1162
1163    return;
1164 }
1165
1166
1167 /*********************************************************************
1168  *
1169  * Function    :  accept_connection
1170  *
1171  * Description :  Accepts a connection on one of possibly multiple
1172  *                sockets. The socket(s) to check must have been
1173  *                created using bind_port().
1174  *
1175  * Parameters  :
1176  *          1  :  csp = Client state, cfd, ip_addr_str, and
1177  *                      ip_addr_long will be set by this routine.
1178  *          2  :  fds = File descriptors returned from bind_port
1179  *
1180  * Returns     :  when a connection is accepted, it returns 1 (TRUE).
1181  *                On an error it returns 0 (FALSE).
1182  *
1183  *********************************************************************/
1184 int accept_connection(struct client_state * csp, jb_socket fds[])
1185 {
1186 #ifdef HAVE_RFC2553
1187    /* XXX: client is stored directly into csp->tcp_addr */
1188 #define client (csp->tcp_addr)
1189 #else
1190    struct sockaddr_in client;
1191 #endif
1192    jb_socket afd;
1193 #if defined(_WIN32)
1194    /* Weirdness - fix a warning. */
1195    int c_length;
1196 #else
1197    socklen_t c_length;
1198 #endif
1199    int retval;
1200    int i;
1201    int max_selected_socket;
1202    struct pollfd poll_fds[MAX_LISTENING_SOCKETS];
1203    nfds_t polled_sockets;
1204    jb_socket fd;
1205    const char *host_addr;
1206    size_t listen_addr_size;
1207
1208    c_length = sizeof(client);
1209
1210    memset(poll_fds, 0, sizeof(poll_fds));
1211    polled_sockets = 0;
1212    max_selected_socket = 0;
1213    for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
1214    {
1215       if (JB_INVALID_SOCKET != fds[i])
1216       {
1217          poll_fds[i].fd = fds[i];
1218          poll_fds[i].events = POLLIN;
1219          polled_sockets++;
1220          if (max_selected_socket < fds[i] + 1)
1221          {
1222             max_selected_socket = fds[i] + 1;
1223          }
1224       }
1225    }
1226    if (0 == max_selected_socket)
1227    {
1228       return 0;
1229    }
1230    do
1231    {
1232       retval = poll(poll_fds, polled_sockets, -1);
1233    } while (retval < 0 && errno == EINTR);
1234    if (retval <= 0)
1235    {
1236       if (0 == retval)
1237       {
1238          log_error(LOG_LEVEL_ERROR,
1239             "Waiting on new client failed because poll(2) returned 0."
1240             " This should not happen.");
1241       }
1242       else
1243       {
1244          log_error(LOG_LEVEL_ERROR,
1245             "Waiting on new client failed because of problems in poll(2): "
1246             "%s.", strerror(errno));
1247       }
1248       return 0;
1249    }
1250    for (i = 0; i < MAX_LISTENING_SOCKETS && (poll_fds[i].revents == 0); i++);
1251    if (i >= MAX_LISTENING_SOCKETS)
1252    {
1253       log_error(LOG_LEVEL_ERROR,
1254          "poll(2) reported connected clients (number = %u, "
1255          "descriptor boundary = %u), but none found.",
1256          retval, max_selected_socket);
1257       return 0;
1258    }
1259    fd = fds[i];
1260
1261    /* Accept selected connection */
1262 #ifdef _WIN32
1263    afd = accept (fd, (struct sockaddr *) &client, &c_length);
1264    if (afd == JB_INVALID_SOCKET)
1265    {
1266       return 0;
1267    }
1268 #else
1269    do
1270    {
1271       afd = accept (fd, (struct sockaddr *) &client, &c_length);
1272    } while (afd < 0 && errno == EINTR);
1273    if (afd < 0)
1274    {
1275       return 0;
1276    }
1277 #endif
1278
1279 #ifdef SO_LINGER
1280    {
1281       struct linger linger_options;
1282       linger_options.l_onoff  = 1;
1283       linger_options.l_linger = 5;
1284       if (0 != setsockopt(afd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options)))
1285       {
1286          log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd);
1287       }
1288    }
1289 #endif
1290
1291 #ifdef FEATURE_EXTERNAL_FILTERS
1292    mark_socket_for_close_on_execute(afd);
1293 #endif
1294
1295    set_no_delay_flag(afd);
1296
1297    csp->cfd = afd;
1298 #ifdef HAVE_RFC2553
1299    csp->ip_addr_str = malloc_or_die(NI_MAXHOST);
1300    retval = getnameinfo((struct sockaddr *) &client, c_length,
1301          csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1302    if (!csp->ip_addr_str || retval)
1303    {
1304       log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s",
1305          (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory");
1306       freez(csp->ip_addr_str);
1307    }
1308 #undef client
1309 #else
1310    csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
1311    csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1312 #endif /* def HAVE_RFC2553 */
1313
1314    /*
1315     * Save the name and port of the accepting socket for later lookup.
1316     *
1317     * The string needs space for strlen(...) + 7 characters:
1318     * strlen(haddr[i]) + 1 (':') + 5 (port digits) + 1 ('\0')
1319     */
1320    host_addr = (csp->config->haddr[i] != NULL) ? csp->config->haddr[i] : "";
1321    listen_addr_size = strlen(host_addr) + 7;
1322    csp->listen_addr_str = malloc_or_die(listen_addr_size);
1323    retval = snprintf(csp->listen_addr_str, listen_addr_size,
1324       "%s:%d", host_addr, csp->config->hport[i]);
1325    if ((-1 == retval) || listen_addr_size <= retval)
1326    {
1327       log_error(LOG_LEVEL_ERROR,
1328          "Server name (%s) and port number (%d) ASCII decimal representation"
1329          "don't fit into %lu bytes",
1330          host_addr, csp->config->hport[i], listen_addr_size);
1331       return 0;
1332    }
1333
1334    return 1;
1335
1336 }
1337
1338
1339 /*********************************************************************
1340  *
1341  * Function    :  resolve_hostname_to_ip
1342  *
1343  * Description :  Resolve a hostname to an internet tcp/ip address.
1344  *                NULL or an empty string resolve to INADDR_ANY.
1345  *
1346  * Parameters  :
1347  *          1  :  host = hostname to resolve
1348  *
1349  * Returns     :  INADDR_NONE => failure, INADDR_ANY or tcp/ip address if successful.
1350  *
1351  *********************************************************************/
1352 unsigned long resolve_hostname_to_ip(const char *host)
1353 {
1354    struct sockaddr_in inaddr;
1355    struct hostent *hostp;
1356 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1357    struct hostent result;
1358 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1359    char hbuf[HOSTENT_BUFFER_SIZE];
1360    int thd_err;
1361 #else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1362    struct hostent_data hdata;
1363 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1364 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1365
1366    if ((host == NULL) || (*host == '\0'))
1367    {
1368       return(INADDR_ANY);
1369    }
1370
1371    memset((char *) &inaddr, 0, sizeof inaddr);
1372
1373    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
1374    {
1375       unsigned int dns_retries = 0;
1376 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
1377       while (gethostbyname_r(host, &result, hbuf,
1378                 HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
1379              && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1380       {
1381          log_error(LOG_LEVEL_ERROR,
1382             "Timeout #%u while trying to resolve %s. Trying again.",
1383             dns_retries, host);
1384       }
1385 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1386       while (NULL == (hostp = gethostbyname_r(host, &result,
1387                                  hbuf, HOSTENT_BUFFER_SIZE, &thd_err))
1388              && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1389       {
1390          log_error(LOG_LEVEL_ERROR,
1391             "Timeout #%u while trying to resolve %s. Trying again.",
1392             dns_retries, host);
1393       }
1394 #elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1395       /*
1396        * XXX: Doesn't retry in case of soft errors.
1397        * Does this gethostbyname_r version set h_errno?
1398        */
1399       if (0 == gethostbyname_r(host, &result, &hdata))
1400       {
1401          hostp = &result;
1402       }
1403       else
1404       {
1405          hostp = NULL;
1406       }
1407 #elif defined(MUTEX_LOCKS_AVAILABLE)
1408       privoxy_mutex_lock(&resolver_mutex);
1409       while (NULL == (hostp = gethostbyname(host))
1410              && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1411       {
1412          log_error(LOG_LEVEL_ERROR,
1413             "Timeout #%u while trying to resolve %s. Trying again.",
1414             dns_retries, host);
1415       }
1416       privoxy_mutex_unlock(&resolver_mutex);
1417 #else
1418       while (NULL == (hostp = gethostbyname(host))
1419              && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
1420       {
1421          log_error(LOG_LEVEL_ERROR,
1422             "Timeout #%u while trying to resolve %s. Trying again.",
1423             dns_retries, host);
1424       }
1425 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1426       /*
1427        * On Mac OSX, if a domain exists but doesn't have a type A
1428        * record associated with it, the h_addr member of the struct
1429        * hostent returned by gethostbyname is NULL, even if h_length
1430        * is 4. Therefore the second test below.
1431        */
1432       if (hostp == NULL || hostp->h_addr == NULL)
1433       {
1434          errno = EINVAL;
1435          log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
1436          return(INADDR_NONE);
1437       }
1438       if (hostp->h_addrtype != AF_INET)
1439       {
1440 #ifdef _WIN32
1441          errno = WSAEPROTOTYPE;
1442 #else
1443          errno = EPROTOTYPE;
1444 #endif
1445          log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
1446          return(INADDR_NONE);
1447       }
1448       memcpy((char *)&inaddr.sin_addr, (char *)hostp->h_addr, sizeof(inaddr.sin_addr));
1449    }
1450    return(inaddr.sin_addr.s_addr);
1451
1452 }
1453
1454
1455 /*********************************************************************
1456  *
1457  * Function    :  socket_is_still_alive
1458  *
1459  * Description :  Figures out whether or not a socket is still alive.
1460  *
1461  * Parameters  :
1462  *          1  :  sfd = The socket to check.
1463  *
1464  * Returns     :  TRUE for yes, otherwise FALSE.
1465  *
1466  *********************************************************************/
1467 int socket_is_still_alive(jb_socket sfd)
1468 {
1469    char buf[10];
1470    int no_data_waiting;
1471    int poll_result;
1472    struct pollfd poll_fd[1];
1473
1474    memset(poll_fd, 0, sizeof(poll_fd));
1475    poll_fd[0].fd = sfd;
1476    poll_fd[0].events = POLLIN;
1477
1478    poll_result = poll(poll_fd, 1, 0);
1479
1480    if (-1 == poll_result)
1481    {
1482       log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd);
1483       return FALSE;
1484    }
1485    no_data_waiting = !(poll_fd[0].revents & POLLIN);
1486
1487    return (no_data_waiting || (1 == recv(sfd, buf, 1, MSG_PEEK)));
1488 }
1489
1490
1491 #ifdef FEATURE_EXTERNAL_FILTERS
1492 /*********************************************************************
1493  *
1494  * Function    :  mark_socket_for_close_on_execute
1495  *
1496  * Description :  Marks a socket for close on execute.
1497  *
1498  *                Used so that external filters have no direct
1499  *                access to sockets they shouldn't care about.
1500  *
1501  *                Not implemented for all platforms.
1502  *
1503  * Parameters  :
1504  *          1  :  fd = The socket to mark
1505  *
1506  * Returns     :  void.
1507  *
1508  *********************************************************************/
1509 void mark_socket_for_close_on_execute(jb_socket fd)
1510 {
1511 #ifdef FEATURE_PTHREAD
1512    int ret;
1513
1514    ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
1515
1516    if (ret == -1)
1517    {
1518       log_error(LOG_LEVEL_ERROR,
1519          "fcntl(%d, F_SETFD, FD_CLOEXEC) failed", fd);
1520    }
1521 #else
1522 #warning "Sockets will be visible to external filters"
1523 #endif
1524 }
1525 #endif /* def FEATURE_EXTERNAL_FILTERS */
1526
1527 /*
1528   Local Variables:
1529   tab-width: 3
1530   end:
1531 */