Hi, I've regenerated the patch with 'hg export' instead of 'hg log -p'. (Sorry, I'm a Mercurial newbie.)
At Sun, 31 Jul 2011 01:41:22 +0900, SATOH Fumiyasu wrote: > Dovecot ignores EINPROGRESS on connect(2) for non-blocking fd. > This is wrong. After that, read(2) to fd (or write(2) to fd) fails > with ENOTCONN if the connection of fd is not completed. > > The attached patch fixes this problem. -- -- Name: SATOH Fumiyasu (fumiyas @ osstech co jp) -- Business Home: http://www.OSSTech.co.jp/ -- Personal Home: http://www.SFO.jp/blog/
# HG changeset patch # User SATOH Fumiyasu <fumi...@osstech.co.jp> # Date 1312003026 -32400 # Branch fumiyas # Node ID 43012b1264013ce316a23d530d2f0c44c2f53f15 # Parent 86c6f58e57568c9e6b9320365af612cf26d5b278 net_connect_*(): Wait for fd to complete connect(2) when fd is non-blocking mode and connect(2) failes with EINPROGRESS or EALREADY. diff -r 86c6f58e5756 -r 43012b126401 src/lib/network.c --- a/src/lib/network.c Sat Jul 30 01:21:35 2011 +0900 +++ b/src/lib/network.c Sat Jul 30 14:17:06 2011 +0900 @@ -5,6 +5,7 @@ #include "fd-set-nonblock.h" #include "time-util.h" #include "network.h" +#include "ioloop.h" #include <stdlib.h> #include <unistd.h> @@ -138,6 +139,11 @@ return 0; } +static void net_connect_in_progress(struct ioloop *ioloop) +{ + io_loop_stop(ioloop); +} + #ifdef __FreeBSD__ static int net_connect_ip_full_freebsd(const struct ip_addr *ip, unsigned int port, @@ -207,16 +213,31 @@ /* connect */ sin_set_ip(&so, ip); sin_set_port(&so, port); - ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so)); + do { + ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so)); + } while (ret < 0 && errno == EINTR); + + if (ret >= 0) { + return fd; + } #ifndef WIN32 - if (ret < 0 && errno != EINPROGRESS) + if (errno != EINPROGRESS && errno != EALREADY) #else - if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) + if (WSAGetLastError() != WSAEWOULDBLOCK) #endif { - close_keep_errno(fd); + close_keep_errno(fd); return -1; + } else { + struct ioloop *ioloop; + struct io *io; + + ioloop = io_loop_create(); + io = io_add(fd, IO_WRITE, net_connect_in_progress, ioloop); + io_loop_run(ioloop); + io_remove(&io); + io_loop_destroy(&ioloop); } return fd; @@ -286,10 +307,26 @@ net_set_nonblock(fd, TRUE); /* connect */ - ret = connect(fd, &sa.sa, sizeof(sa)); - if (ret < 0 && errno != EINPROGRESS) { - close_keep_errno(fd); + do { + ret = connect(fd, &sa.sa, sizeof(sa)); + } while (ret < 0 && errno == EINTR); + + if (ret >= 0) { + return fd; + } + + if (errno != EINPROGRESS && errno != EALREADY) { + close_keep_errno(fd); return -1; + } else { + struct ioloop *ioloop; + struct io *io; + + ioloop = io_loop_create(); + io = io_add(fd, IO_WRITE, net_connect_in_progress, ioloop); + io_loop_run(ioloop); + io_remove(&io); + io_loop_destroy(&ioloop); } return fd;