diff options
author | kosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-05-04 02:44:28 +0000 |
---|---|---|
committer | kosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-05-04 02:44:28 +0000 |
commit | 9851b0ce2fbc5934ddd00434048be4273f41102d (patch) | |
tree | bdd27a175928e98de6e1dca086a5d052b52e56d3 /ext/socket | |
parent | 4da4cb0421fbdd5c7a825addcda9c8725e86c844 (diff) |
* 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
Diffstat (limited to 'ext/socket')
-rw-r--r-- | ext/socket/init.c | 38 |
1 files changed, 29 insertions, 9 deletions
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__ |