diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-09-21 18:46:48 +0400 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-09-21 18:46:48 +0400 |
commit | f11a1c737f7e1d524d8b8bc056a531ab0f669d8e (patch) | |
tree | dabc7393b9bfa3749c267542f21dcbec250602fa /src/util.c | |
parent | 08a5507e764cbdfd0ee1f80a864d906d12071a35 (diff) | |
download | rspamd-f11a1c737f7e1d524d8b8bc056a531ab0f669d8e.tar.gz rspamd-f11a1c737f7e1d524d8b8bc056a531ab0f669d8e.zip |
* Add time out for sync IO as it can cause unpredictable errors
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/src/util.c b/src/util.c index ba06c570e..2e18c441a 100644 --- a/src/util.c +++ b/src/util.c @@ -32,6 +32,8 @@ #define CHECK_TIME 60 /* More than 2 log messages per second */ #define BUF_INTENSITY 2 +/* Default connect timeout for sync sockets */ +#define CONNECT_TIMEOUT 3 #ifdef RSPAMD_MAIN sig_atomic_t do_reopen_log = 0; @@ -54,13 +56,49 @@ static gboolean log_buffered = FALSE; int make_socket_nonblocking (int fd) { - if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + int ofl; + + ofl = fcntl (fd, F_GETFL, 0); + + if (fcntl (fd, F_SETFL, ofl | O_NONBLOCK) == -1) { + msg_warn ("make_socket_nonblocking: fcntl failed: %d, '%s'", errno, strerror (errno)); + return -1; + } + return 0; +} + +int +make_socket_blocking (int fd) +{ + int ofl; + + ofl = fcntl (fd, F_GETFL, 0); + + if (fcntl (fd, F_SETFL, ofl & (~O_NONBLOCK)) == -1) { msg_warn ("make_socket_nonblocking: fcntl failed: %d, '%s'", errno, strerror (errno)); return -1; } return 0; } +static int +poll_sync_socket (int fd, int timeout, short events) +{ + int r; + struct pollfd fds[1]; + + fds->fd = fd; + fds->events = events; + fds->revents = 0; + while ((r = poll (fds, 1, timeout)) < 0) { + if (errno != EINTR) { + break; + } + } + + return r; +} + static int make_inet_socket (int family, struct in_addr *addr, u_short port, gboolean is_server, gboolean async) { @@ -75,7 +113,7 @@ make_inet_socket (int family, struct in_addr *addr, u_short port, gboolean is_se return -1; } - if (async && make_socket_nonblocking(fd) < 0) { + if (make_socket_nonblocking (fd) < 0) { goto out; } @@ -99,10 +137,24 @@ make_inet_socket (int family, struct in_addr *addr, u_short port, gboolean is_se } if (r == -1) { - if (!async || errno != EINPROGRESS) { + if (errno != EINPROGRESS) { msg_warn ("make_tcp_socket: bind/connect failed: %d, '%s'", errno, strerror (errno)); goto out; } + if (!async) { + /* Try to poll */ + if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) { + errno = ETIMEDOUT; + msg_warn ("make_tcp_socket: bind/connect failed: timeout"); + goto out; + } + else { + /* Make synced again */ + if (make_socket_blocking (fd) < 0) { + goto out; + } + } + } } else { /* Still need to check SO_ERROR on socket */ |