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;

Reply via email to