From 9851b0ce2fbc5934ddd00434048be4273f41102d Mon Sep 17 00:00:00 2001 From: kosaki Date: Wed, 4 May 2011 02:44:28 +0000 Subject: * ext/socket/init.c (wait_connectable): fix error handling code. RB_WAITFD_OUT is turned on even though an error occur. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31424 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/socket/init.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'ext/socket/init.c') diff --git a/ext/socket/init.c b/ext/socket/init.c index 4c32ab4720..e55736cabe 100644 --- a/ext/socket/init.c +++ b/ext/socket/init.c @@ -258,22 +258,42 @@ wait_connectable(int fd) { int sockerr; socklen_t sockerrlen; - int r; + int revents; + int ret; for (;;) { - r = rb_wait_for_single_fd(fd, RB_WAITFD_OUT|RB_WAITFD_PRI, NULL); - if ((r > 0) && (r & RB_WAITFD_OUT)) - return 0; - - sockerrlen = (socklen_t)sizeof(sockerr); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, - &sockerrlen) == 0) { + /* + * Stevens book says, succuessful finish turn on RB_WAITFD_OUT and + * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT. + */ + revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL); + + if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) { + sockerrlen = (socklen_t)sizeof(sockerr); + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); + + /* + * Solaris getsockopt(SO_ERROR) return -1 and set errno + * in getsockopt(). Let's return immediately. + */ + if (ret < 0) + break; if (sockerr == 0) continue; /* workaround for winsock */ + + /* BSD and Linux use sockerr. */ errno = sockerr; + ret = -1; + break; + } + + if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) { + ret = 0; + break; } - return -1; } + + return ret; } #ifdef __CYGWIN__ -- cgit v1.2.3