aboutsummaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-21 18:46:48 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-21 18:46:48 +0400
commitf11a1c737f7e1d524d8b8bc056a531ab0f669d8e (patch)
treedabc7393b9bfa3749c267542f21dcbec250602fa /src/util.c
parent08a5507e764cbdfd0ee1f80a864d906d12071a35 (diff)
downloadrspamd-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.c58
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 */