X-Git-Url: http://www.privoxy.org/gitweb/misc.html?a=blobdiff_plain;f=jbsockets.c;h=1c4db6830986d0704f112ef8c4a9a430a8064ce2;hb=65f07bce7c5c11d3239d6d7b27fad94b622f746c;hp=5bdfcb18e3a19cb562be27f1224fbeff87618e50;hpb=b081249a57fcdcd2990db66e384d5a15dc2dc4cf;p=privoxy.git
diff --git a/jbsockets.c b/jbsockets.c
index 5bdfcb18..1c4db683 100644
--- a/jbsockets.c
+++ b/jbsockets.c
@@ -1,15 +1,14 @@
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.120 2013/01/01 22:11:08 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
*
* Purpose : Contains wrappers for system-specific sockets code,
- * so that the rest of Junkbuster can be more
+ * so that the rest of Privoxy can be more
* OS-independent. Contains #ifdefs to make this work
* on many platforms.
*
- * Copyright : Written by and Copyright (C) 2001-2011 the
- * Privoxy team. http://www.privoxy.org/
+ * Copyright : Written by and Copyright (C) 2001-2022 the
+ * Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
* by and Copyright (C) 1997 Anonymous Coders and
@@ -50,15 +49,14 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.120 2013/01/01 22:11:08 fabia
#ifndef STRICT
#define STRICT
#endif
+#include
#include
#include
#include
#else
-#ifndef __OS2__
#include
-#endif
#include
#include
#include
@@ -67,20 +65,11 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.120 2013/01/01 22:11:08 fabia
#ifndef __BEOS__
#include
-#ifndef __OS2__
#include
-#endif
#else
#include
#endif
-#if defined(__EMX__) || defined (__OS2__)
-#include /* OS/2/EMX needs a little help with select */
-#ifdef __OS2__
-#include
-#endif
-#endif
-
#endif
#ifdef HAVE_POLL
@@ -99,14 +88,13 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.120 2013/01/01 22:11:08 fabia
#include "jbsockets.h"
#include "filters.h"
#include "errlog.h"
+#include "miscutil.h"
/* Mac OSX doesn't define AI_NUMERICSESRV */
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif
-const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
-
/*
* Maximum number of gethostbyname(_r) retries in case of
* soft errors (TRY_AGAIN).
@@ -114,14 +102,40 @@ const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
*/
#define MAX_DNS_RETRIES 10
-#define MAX_LISTEN_BACKLOG 128
-
#ifdef HAVE_RFC2553
static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp);
#else
static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp);
#endif
+/*********************************************************************
+ *
+ * Function : set_no_delay_flag
+ *
+ * Description : Disables the Nagle algorithm (TCP send coalescence)
+ * for the given socket.
+ *
+ * Parameters :
+ * 1 : fd = The file descriptor to operate on
+ *
+ * Returns : void
+ *
+ *********************************************************************/
+static void set_no_delay_flag(int fd)
+{
+#ifdef TCP_NODELAY
+ int mi = 1;
+
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &mi, sizeof(int)))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to disable TCP coalescence for socket %d", fd);
+ }
+#else
+#warning set_no_delay_flag() is a nop due to lack of TCP_NODELAY
+#endif /* def TCP_NODELAY */
+}
+
/*********************************************************************
*
* Function : connect_to
@@ -131,7 +145,7 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
*
* Parameters :
* 1 : host = hostname to connect to
- * 2 : portnum = port to connent on (XXX: should be unsigned)
+ * 2 : portnum = port to connect to (XXX: should be unsigned)
* 3 : csp = Current client state (buffers, headers, etc...)
*
* Returns : JB_INVALID_SOCKET => failure, else it is the socket
@@ -182,14 +196,18 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
char service[6];
int retval;
jb_socket fd;
+#ifdef HAVE_POLL
+ struct pollfd poll_fd[1];
+#else
fd_set wfds;
struct timeval timeout;
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#endif
+#if !defined(_WIN32) && !defined(__BEOS__)
int flags;
#endif
int connect_failed;
/*
- * XXX: Initializeing it here is only necessary
+ * XXX: Initializing it here is only necessary
* because not all situations are properly
* covered yet.
*/
@@ -225,21 +243,14 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
{
log_error(LOG_LEVEL_INFO,
"Can not resolve %s: %s", host, gai_strerror(retval));
- /* XXX: Should find a better way to propagate this error. */
- errno = EINVAL;
csp->error_message = strdup(gai_strerror(retval));
csp->http->host_ip_addr_str = strdup("unknown");
+ /* XXX: Should find a better way to propagate this error. */
+ errno = EINVAL;
return(JB_INVALID_SOCKET);
}
- csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
- if (NULL == csp->http->host_ip_addr_str)
- {
- freeaddrinfo(result);
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the server IP address.");
- return JB_INVALID_SOCKET;
- }
+ csp->http->host_ip_addr_str = malloc_or_die(NI_MAXHOST);
for (rp = result; rp != NULL; rp = rp->ai_next)
{
@@ -249,11 +260,7 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
if (block_acl(dst, csp))
{
-#ifdef __OS2__
- socket_error = errno = SOCEPERM;
-#else
socket_error = errno = EPERM;
-#endif
continue;
}
#endif /* def FEATURE_ACL */
@@ -278,6 +285,7 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
continue;
}
+#ifndef HAVE_POLL
#ifndef _WIN32
if (fd >= FD_SETSIZE)
{
@@ -285,37 +293,34 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
"Server socket number too high to use select(): %d >= %d",
fd, FD_SETSIZE);
close_socket(fd);
+ freeaddrinfo(result);
return JB_INVALID_SOCKET;
}
#endif
+#endif
-#ifdef TCP_NODELAY
- { /* turn off TCP coalescence */
- int mi = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
- }
-#endif /* def TCP_NODELAY */
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
+
+ set_no_delay_flag(fd);
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(__BEOS__)
if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
{
flags |= O_NDELAY;
fcntl(fd, F_SETFL, flags);
}
-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+#endif /* !defined(_WIN32) && !defined(__BEOS__) */
connect_failed = 0;
while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
{
-#ifdef __OS2__
- errno = sock_errno();
-#endif /* __OS2__ */
-
#ifdef _WIN32
if (errno == WSAEINPROGRESS)
#else /* ifndef _WIN32 */
if (errno == EINPROGRESS)
-#endif /* ndef _WIN32 || __OS2__ */
+#endif /* ndef _WIN32 */
{
break;
}
@@ -333,14 +338,39 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
continue;
}
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(__BEOS__)
if (flags != -1)
{
flags &= ~O_NDELAY;
fcntl(fd, F_SETFL, flags);
}
-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+#endif /* !defined(_WIN32) && !defined(__BEOS__) */
+
+#ifdef HAVE_POLL
+ poll_fd[0].fd = fd;
+ poll_fd[0].events = POLLOUT;
+ retval = poll(poll_fd, 1, 30000);
+ if (retval == 0)
+ {
+ if (rp->ai_next != NULL)
+ {
+ /* Log this now as we'll try another address next */
+ log_error(LOG_LEVEL_CONNECT,
+ "Could not connect to [%s]:%s: Operation timed out.",
+ csp->http->host_ip_addr_str, service);
+ }
+ else
+ {
+ /*
+ * This is the last address, don't log this now
+ * as it would result in a duplicated log message.
+ */
+ socket_error = ETIMEDOUT;
+ }
+ }
+ else if (retval > 0)
+#else
/* wait for connection to complete */
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
@@ -351,6 +381,7 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
/* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */
if ((select((int)fd + 1, NULL, &wfds, NULL, &timeout) > 0)
&& FD_ISSET(fd, &wfds))
+#endif
{
socklen_t optlen = sizeof(socket_error);
if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &optlen))
@@ -408,9 +439,13 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
struct sockaddr_in inaddr;
jb_socket fd;
unsigned int addr;
+#ifdef HAVE_POLL
+ struct pollfd poll_fd[1];
+#else
fd_set wfds;
struct timeval tv[1];
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#endif
+#if !defined(_WIN32) && !defined(__BEOS__)
int flags;
#endif
@@ -435,11 +470,7 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
if (block_acl(dst, csp))
{
-#ifdef __OS2__
- errno = SOCEPERM;
-#else
errno = EPERM;
-#endif
return(JB_INVALID_SOCKET);
}
#endif /* def FEATURE_ACL */
@@ -471,6 +502,7 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
return(JB_INVALID_SOCKET);
}
+#ifndef HAVE_POLL
#ifndef _WIN32
if (fd >= FD_SETSIZE)
{
@@ -480,55 +512,54 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
close_socket(fd);
return JB_INVALID_SOCKET;
}
+#endif
#endif
-#ifdef TCP_NODELAY
- { /* turn off TCP coalescence */
- int mi = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
- }
-#endif /* def TCP_NODELAY */
+ set_no_delay_flag(fd);
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(__BEOS__)
if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
{
flags |= O_NDELAY;
fcntl(fd, F_SETFL, flags);
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
}
-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+#endif /* !defined(_WIN32) && !defined(__BEOS__) */
while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
{
#ifdef _WIN32
if (errno == WSAEINPROGRESS)
-#elif __OS2__
- if (sock_errno() == EINPROGRESS)
#else /* ifndef _WIN32 */
if (errno == EINPROGRESS)
-#endif /* ndef _WIN32 || __OS2__ */
+#endif /* ndef _WIN32 */
{
break;
}
-#ifdef __OS2__
- if (sock_errno() != EINTR)
-#else
if (errno != EINTR)
-#endif /* __OS2__ */
{
close_socket(fd);
return(JB_INVALID_SOCKET);
}
}
-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(__BEOS__)
if (flags != -1)
{
flags &= ~O_NDELAY;
fcntl(fd, F_SETFL, flags);
}
-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+#endif /* !defined(_WIN32) && !defined(__BEOS__) */
+#ifdef HAVE_POLL
+ poll_fd[0].fd = fd;
+ poll_fd[0].events = POLLOUT;
+
+ if (poll(poll_fd, 1, 30000) <= 0)
+#else
/* wait for connection to complete */
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
@@ -538,6 +569,7 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
/* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */
if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
+#endif
{
close_socket(fd);
return(JB_INVALID_SOCKET);
@@ -563,47 +595,84 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
* nonzero on error.
*
*********************************************************************/
-#ifdef AMIGA
-int write_socket(jb_socket fd, const char *buf, ssize_t len)
-#else
int write_socket(jb_socket fd, const char *buf, size_t len)
-#endif
{
if (len == 0)
{
return 0;
}
+#ifdef FUZZ
+ if (!daemon_mode && fd <= 3)
+ {
+ log_error(LOG_LEVEL_WRITING, "Pretending to write to socket %d: %N", fd, len, buf);
+ return 0;
+ }
+#endif
+
log_error(LOG_LEVEL_WRITING, "to socket %d: %N", fd, len, buf);
#if defined(_WIN32)
return (send(fd, buf, (int)len, 0) != (int)len);
-#elif defined(__BEOS__) || defined(AMIGA)
+#elif defined(__BEOS__)
return (send(fd, buf, len, 0) != len);
-#elif defined(__OS2__)
- /*
- * Break the data up into SOCKET_SEND_MAX chunks for sending...
- * OS/2 seemed to complain when the chunks were too large.
- */
-#define SOCKET_SEND_MAX 65000
+#else
+ return (write(fd, buf, len) != len);
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : write_socket_delayed
+ *
+ * Description : Write the contents of buf (for n bytes) to
+ * socket fd, optionally delaying the operation.
+ *
+ * Parameters :
+ * 1 : fd = File descriptor (aka. handle) of socket to write to.
+ * 2 : buf = Pointer to data to be written.
+ * 3 : len = Length of data to be written to the socket "fd".
+ * 4 : delay = Delay in milliseconds.
+ *
+ * Returns : 0 on success (entire buffer sent).
+ * nonzero on error.
+ *
+ *********************************************************************/
+int write_socket_delayed(jb_socket fd, const char *buf, size_t len, unsigned int delay)
+{
+ size_t i = 0;
+
+ if (delay == 0)
{
- int send_len, send_rc = 0, i = 0;
- while ((i < len) && (send_rc != -1))
+ return write_socket(fd, buf, len);
+ }
+
+ while (i < len)
+ {
+ size_t write_length;
+ enum {MAX_WRITE_LENGTH = 10};
+
+ if ((i + MAX_WRITE_LENGTH) > len)
{
- if ((i + SOCKET_SEND_MAX) > len)
- send_len = len - i;
- else
- send_len = SOCKET_SEND_MAX;
- send_rc = send(fd,(char*)buf + i, send_len, 0);
- if (send_rc == -1)
- return 1;
- i = i + send_len;
+ write_length = len - i;
}
- return 0;
+ else
+ {
+ write_length = MAX_WRITE_LENGTH;
+ }
+
+ privoxy_millisleep(delay);
+
+ if (write_socket(fd, buf + i, write_length) != 0)
+ {
+ return 1;
+ }
+ i += write_length;
}
-#else
- return (write(fd, buf, len) != len);
-#endif
+
+ return 0;
}
@@ -644,7 +713,7 @@ int read_socket(jb_socket fd, char *buf, int len)
#if defined(_WIN32)
ret = recv(fd, buf, len, 0);
-#elif defined(__BEOS__) || defined(AMIGA) || defined(__OS2__)
+#elif defined(__BEOS__)
ret = recv(fd, buf, (size_t)len, 0);
#else
ret = (int)read(fd, buf, (size_t)len);
@@ -675,23 +744,27 @@ int read_socket(jb_socket fd, char *buf, int len)
*********************************************************************/
int data_is_available(jb_socket fd, int seconds_to_wait)
{
+ int n;
char buf[10];
+#ifdef HAVE_POLL
+ struct pollfd poll_fd[1];
+
+ poll_fd[0].fd = fd;
+ poll_fd[0].events = POLLIN;
+
+ n = poll(poll_fd, 1, seconds_to_wait * 1000);
+#else
fd_set rfds;
struct timeval timeout;
- int n;
memset(&timeout, 0, sizeof(timeout));
timeout.tv_sec = seconds_to_wait;
-#ifdef __OS2__
- /* Copy and pasted from jcc.c ... */
- memset(&rfds, 0, sizeof(fd_set));
-#else
FD_ZERO(&rfds);
-#endif
FD_SET(fd, &rfds);
n = select(fd+1, &rfds, NULL, NULL, &timeout);
+#endif
/*
* XXX: Do we care about the different error conditions?
@@ -716,10 +789,6 @@ void close_socket(jb_socket fd)
{
#if defined(_WIN32) || defined(__BEOS__)
closesocket(fd);
-#elif defined(AMIGA)
- CloseSocket(fd);
-#elif defined(__OS2__)
- soclose(fd);
#else
close(fd);
#endif
@@ -781,7 +850,7 @@ void drain_and_close_socket(jb_socket fd)
bytes_drained_total += bytes_drained;
if (bytes_drained_total > ARBITRARY_DRAIN_LIMIT)
{
- log_error(LOG_LEVEL_CONNECT, "Giving up draining socket %d", fd);
+ log_error(LOG_LEVEL_CONNECT, "Giving up draining socket %d.", fd);
break;
}
}
@@ -789,7 +858,7 @@ void drain_and_close_socket(jb_socket fd)
if (bytes_drained_total != 0)
{
log_error(LOG_LEVEL_CONNECT,
- "Drained %d bytes before closing socket %d", bytes_drained_total, fd);
+ "Drained %d bytes before closing socket %d.", bytes_drained_total, fd);
}
}
@@ -808,14 +877,15 @@ void drain_and_close_socket(jb_socket fd)
* Parameters :
* 1 : hostnam = TCP/IP address to bind/listen to
* 2 : portnum = port to listen on
- * 3 : pfd = pointer used to return file descriptor.
+ * 3 : backlog = Listen backlog
+ * 4 : pfd = pointer used to return file descriptor.
*
* Returns : if success, returns 0 and sets *pfd.
* if failure, returns -3 if address is in use,
* -2 if address unresolvable,
* -1 otherwise
*********************************************************************/
-int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
+int bind_port(const char *hostnam, int portnum, int backlog, jb_socket *pfd)
{
#ifdef HAVE_RFC2553
struct addrinfo hints;
@@ -842,7 +912,7 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
if ((-1 == retval) || (sizeof(servnam) <= retval))
{
log_error(LOG_LEVEL_ERROR,
- "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
+ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes.",
portnum);
return -1;
}
@@ -921,6 +991,10 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
#endif
}
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
+
#ifndef _WIN32
/*
* This is not needed for Win32 - in fact, it stops
@@ -937,6 +1011,10 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
#endif /* ndef _WIN32 */
+#ifdef IP_FREEBIND
+ setsockopt(fd, IPPROTO_IP, IP_FREEBIND, (char *)&one, sizeof(one));
+#endif
+
#ifdef HAVE_RFC2553
if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
#else
@@ -986,10 +1064,11 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
}
#endif /* ndef HAVE_RFC2553 */
- while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
+ while (listen(fd, backlog) == -1)
{
if (errno != EINTR)
{
+ close_socket(fd);
return(-1);
}
}
@@ -1034,7 +1113,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
struct sockaddr_in server;
struct hostent *host = NULL;
#endif /* HAVE_RFC2553 */
-#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+#if defined(_WIN32)
/* according to accept_connection() this fixes a warning. */
int s_length, s_length_provided;
#else
@@ -1072,27 +1151,15 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
* configured with --disable-ipv6-support.
* The proper fix is to not use NI_MAXSERV in
* that case. It works by accident on other platforms
- * as in included unconditionally there.
+ * as is included unconditionally there.
*/
#ifndef NI_MAXSERV
#define NI_MAXSERV 32
#endif
- *port = malloc(NI_MAXSERV);
- if (NULL == *port)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's port.");
- return;
- }
+ *port = malloc_or_die(NI_MAXSERV);
+
#ifdef HAVE_RFC2553
- *ip_address = malloc(NI_MAXHOST);
- if (NULL == *ip_address)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's IP address.");
- freez(*port);
- return;
- }
+ *ip_address = malloc_or_die(NI_MAXHOST);
retval = getnameinfo((struct sockaddr *) &server, s_length,
*ip_address, NI_MAXHOST, *port, NI_MAXSERV,
NI_NUMERICHOST|NI_NUMERICSERV);
@@ -1118,13 +1185,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
}
#ifdef HAVE_RFC2553
- *hostname = malloc(NI_MAXHOST);
- if (NULL == *hostname)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's hostname.");
- return;
- }
+ *hostname = malloc_or_die(NI_MAXHOST);
retval = getnameinfo((struct sockaddr *) &server, s_length,
*hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
if (retval)
@@ -1204,8 +1265,8 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
struct sockaddr_in client;
#endif
jb_socket afd;
-#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
- /* Wierdness - fix a warning. */
+#if defined(_WIN32)
+ /* Weirdness - fix a warning. */
int c_length;
#else
socklen_t c_length;
@@ -1213,23 +1274,41 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
int retval;
int i;
int max_selected_socket;
+#ifdef HAVE_POLL
+ struct pollfd poll_fds[MAX_LISTENING_SOCKETS];
+ nfds_t polled_sockets;
+#else
fd_set selected_fds;
+#endif
jb_socket fd;
+ const char *host_addr;
+ size_t listen_addr_size;
c_length = sizeof(client);
+#ifdef HAVE_POLL
+ memset(poll_fds, 0, sizeof(poll_fds));
+ polled_sockets = 0;
+#else
/*
* Wait for a connection on any socket.
* Return immediately if no socket is listening.
* XXX: Why not treat this as fatal error?
*/
FD_ZERO(&selected_fds);
+#endif
max_selected_socket = 0;
for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
{
if (JB_INVALID_SOCKET != fds[i])
{
+#ifdef HAVE_POLL
+ poll_fds[i].fd = fds[i];
+ poll_fds[i].events = POLLIN;
+ polled_sockets++;
+#else
FD_SET(fds[i], &selected_fds);
+#endif
if (max_selected_socket < fds[i] + 1)
{
max_selected_socket = fds[i] + 1;
@@ -1242,7 +1321,11 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
}
do
{
+#ifdef HAVE_POLL
+ retval = poll(poll_fds, polled_sockets, -1);
+#else
retval = select(max_selected_socket, &selected_fds, NULL, NULL, NULL);
+#endif
} while (retval < 0 && errno == EINTR);
if (retval <= 0)
{
@@ -1260,8 +1343,12 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
}
return 0;
}
+#ifdef HAVE_POLL
+ for (i = 0; i < MAX_LISTENING_SOCKETS && (poll_fds[i].revents == 0); i++);
+#else
for (i = 0; i < MAX_LISTENING_SOCKETS && !FD_ISSET(fds[i], &selected_fds);
i++);
+#endif
if (i >= MAX_LISTENING_SOCKETS)
{
log_error(LOG_LEVEL_ERROR,
@@ -1282,14 +1369,8 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
#else
do
{
-#if defined(FEATURE_ACCEPT_FILTER) && defined(SO_ACCEPTFILTER)
- struct accept_filter_arg af_options;
- bzero(&af_options, sizeof(af_options));
- strlcpy(af_options.af_name, "httpready", sizeof(af_options.af_name));
- setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &af_options, sizeof(af_options));
-#endif
afd = accept (fd, (struct sockaddr *) &client, &c_length);
- } while (afd < 1 && errno == EINTR);
+ } while (afd < 0 && errno == EINTR);
if (afd < 0)
{
return 0;
@@ -1301,13 +1382,14 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
struct linger linger_options;
linger_options.l_onoff = 1;
linger_options.l_linger = 5;
- if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options)))
+ if (0 != setsockopt(afd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options)))
{
log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd);
}
}
#endif
+#ifndef HAVE_POLL
#ifndef _WIN32
if (afd >= FD_SETSIZE)
{
@@ -1318,16 +1400,17 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
return 0;
}
#endif
+#endif
+
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(afd);
+#endif
+
+ set_no_delay_flag(afd);
csp->cfd = afd;
#ifdef HAVE_RFC2553
- csp->ip_addr_str = malloc(NI_MAXHOST);
- if (NULL == csp->ip_addr_str)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's IP address.");
- return 0;
- }
+ csp->ip_addr_str = malloc_or_die(NI_MAXHOST);
retval = getnameinfo((struct sockaddr *) &client, c_length,
csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (!csp->ip_addr_str || retval)
@@ -1342,6 +1425,26 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
#endif /* def HAVE_RFC2553 */
+ /*
+ * Save the name and port of the accepting socket for later lookup.
+ *
+ * The string needs space for strlen(...) + 7 characters:
+ * strlen(haddr[i]) + 1 (':') + 5 (port digits) + 1 ('\0')
+ */
+ host_addr = (csp->config->haddr[i] != NULL) ? csp->config->haddr[i] : "";
+ listen_addr_size = strlen(host_addr) + 7;
+ csp->listen_addr_str = malloc_or_die(listen_addr_size);
+ retval = snprintf(csp->listen_addr_str, listen_addr_size,
+ "%s:%d", host_addr, csp->config->hport[i]);
+ if ((-1 == retval) || listen_addr_size <= retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Server name (%s) and port number (%d) ASCII decimal representation "
+ "don't fit into %lu bytes",
+ host_addr, csp->config->hport[i], listen_addr_size);
+ return 0;
+ }
+
return 1;
}
@@ -1479,7 +1582,6 @@ int socket_is_still_alive(jb_socket sfd)
{
char buf[10];
int no_data_waiting;
-
#ifdef HAVE_POLL
int poll_result;
struct pollfd poll_fd[1];
@@ -1518,6 +1620,42 @@ int socket_is_still_alive(jb_socket sfd)
}
+#ifdef FEATURE_EXTERNAL_FILTERS
+/*********************************************************************
+ *
+ * Function : mark_socket_for_close_on_execute
+ *
+ * Description : Marks a socket for close on execute.
+ *
+ * Used so that external filters have no direct
+ * access to sockets they shouldn't care about.
+ *
+ * Not implemented for all platforms.
+ *
+ * Parameters :
+ * 1 : fd = The socket to mark
+ *
+ * Returns : void.
+ *
+ *********************************************************************/
+void mark_socket_for_close_on_execute(jb_socket fd)
+{
+#ifdef FEATURE_PTHREAD
+ int ret;
+
+ ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ if (ret == -1)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "fcntl(%d, F_SETFD, FD_CLOEXEC) failed", fd);
+ }
+#else
+#warning "Sockets will be visible to external filters"
+#endif
+}
+#endif /* def FEATURE_EXTERNAL_FILTERS */
+
/*
Local Variables:
tab-width: 3