aboutsummaryrefslogtreecommitdiffstats
path: root/lang/ruby18
diff options
context:
space:
mode:
authorstas <stas@FreeBSD.org>2009-02-23 08:41:07 +0800
committerstas <stas@FreeBSD.org>2009-02-23 08:41:07 +0800
commit6efafb066b5fa1766240cab3e739379a4489c8b4 (patch)
treee0e7e90db8de7499afd9fe391998bf2469ca4002 /lang/ruby18
parentc3e7221fe0455c739aed67cc998ae239ca7f4db4 (diff)
downloadfreebsd-ports-gnome-6efafb066b5fa1766240cab3e739379a4489c8b4.tar.gz
freebsd-ports-gnome-6efafb066b5fa1766240cab3e739379a4489c8b4.tar.zst
freebsd-ports-gnome-6efafb066b5fa1766240cab3e739379a4489c8b4.zip
- Ruby socket connect code seems to work unstably in case if connection
to remote host was refused. FreeBSD connect(2) call returns EINVAL in that case and clears the error code, so there's no way to determine what happened. Reimplement ruby_connect via select call instead of polling the status by connect(2). This may also reduce overhead (though, not verified). Reported by: Saku Ytti <saku@ytti.fi>
Diffstat (limited to 'lang/ruby18')
-rw-r--r--lang/ruby18/files/patch-ext_socket_socket.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/lang/ruby18/files/patch-ext_socket_socket.c b/lang/ruby18/files/patch-ext_socket_socket.c
new file mode 100644
index 000000000000..86092a459d58
--- /dev/null
+++ b/lang/ruby18/files/patch-ext_socket_socket.c
@@ -0,0 +1,105 @@
+--- ext/socket/socket.c.orig 2009-02-23 00:54:12.000000000 +0300
++++ ext/socket/socket.c 2009-02-23 01:27:13.000000000 +0300
+@@ -1111,81 +1111,33 @@
+ fcntl(fd, F_SETFL, mode|NONBLOCKING);
+ #endif /* HAVE_FCNTL */
+
+- for (;;) {
+ #if defined(SOCKS) && !defined(SOCKS5)
+- if (socks) {
+- status = Rconnect(fd, sockaddr, len);
+- }
+- else
+-#endif
+- {
+- status = connect(fd, sockaddr, len);
+- }
+- if (status < 0) {
+- switch (errno) {
+- case EAGAIN:
+-#ifdef EINPROGRESS
+- case EINPROGRESS:
+-#endif
+-#if WAIT_IN_PROGRESS > 0
+- sockerrlen = sizeof(sockerr);
+- status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
+- if (status) break;
+- if (sockerr) {
+- status = -1;
+- errno = sockerr;
+- break;
+- }
+-#endif
+-#ifdef EALREADY
+- case EALREADY:
+-#endif
+-#if WAIT_IN_PROGRESS > 0
+- wait_in_progress = WAIT_IN_PROGRESS;
+-#endif
+- status = wait_connectable(fd);
+- if (status) {
+- break;
+- }
+- errno = 0;
+- continue;
+-
+-#if WAIT_IN_PROGRESS > 0
+- case EINVAL:
+- if (wait_in_progress-- > 0) {
+- /*
+- * connect() after EINPROGRESS returns EINVAL on
+- * some platforms, need to check true error
+- * status.
+- */
+- sockerrlen = sizeof(sockerr);
+- status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
+- if (!status && !sockerr) {
+- struct timeval tv = {0, 100000};
+- rb_thread_wait_for(tv);
+- continue;
+- }
+- status = -1;
+- errno = sockerr;
+- }
+- break;
+-#endif
+-
+-#ifdef EISCONN
+- case EISCONN:
+- status = 0;
+- errno = 0;
+- break;
++ if (socks) {
++ status = Rconnect(fd, sockaddr, len);
++ }
++ else
+ #endif
+- default:
+- break;
++ {
++ status = connect(fd, sockaddr, len);
++ }
++
++ if (status < 0 && (errno == EINPROGRESS || errno == EWOULDBLOCK)) {
++ status = wait_connectable(fd);
++ if (status == 0) {
++ int buf;
++ char c;
++ int len = sizeof(buf);
++ status = getpeername(fd, (struct sockaddr *)&buf, &len);
++ if (status == -1) {
++ read(fd, &c, 1); /* set errno. */
+ }
+ }
++ }
++
+ #ifdef HAVE_FCNTL
+- fcntl(fd, F_SETFL, mode);
++ fcntl(fd, F_SETFL, mode);
+ #endif
+- return status;
+- }
++ return status;
+ }
+
+ struct inetsock_arg