summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/socket/init.c38
2 files changed, 34 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index a0278fb27a..dae0b4f4eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed May 4 11:42:47 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/socket/init.c (wait_connectable): fix error handling code.
+ RB_WAITFD_OUT is turned on even though an error occur.
+
Wed May 4 10:12:39 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* ext/readline/readline.c (readline_event): use rb_wait_for_single_fd().
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__