From: "jeremyevans0 (Jeremy Evans)" Date: 2022-05-24T19:51:55+00:00 Subject: [ruby-core:108678] [Ruby master Bug#18791] Unexpected behavior of Socket#connect_nonblock Issue #18791 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Rejected This doesn't look like a bug. If the `connect` system call returns `0`, then you were able to connect, and `connect_nonblock` in Ruby returns `0` as well. Yes, you should treat `0` as indicating the connection was successful. The documentation states `Returns 0 if successful, otherwise an exception is raised.` I think that explains the behavior correctly, so this does not appear to be a documentation bug either. I think maybe you are expecting `Errno::EISCONN` must be raised to indicate a successful connection. That would also indicate a successful connection, but having the method return `0` also indicates the connection was successful. The example code is written so either returning `0` or raising `Errno::EISCONN` is treated as a successful connection, so the example code does not appear to be incorrect. ---------------------------------------- Bug #18791: Unexpected behavior of Socket#connect_nonblock https://bugs.ruby-lang.org/issues/18791#change-97719 * Author: midnight (Sarun R) * Status: Rejected * Priority: Normal * ruby -v: ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- I followed an example of [Socket#connect_nonblock](https://ruby-doc.org/stdlib-3.1.2/libdoc/socket/rdoc/Socket.html#method-i-connect_nonblock) on the document. Waiting for multiple Socket connections at once. ~~~Ruby # Pull down Google's web page require 'socket' include Socket::Constants socket = Socket.new(AF_INET, SOCK_STREAM, 0) sockaddr = Socket.sockaddr_in(80, 'www.google.com') begin # emulate blocking connect socket.connect_nonblock(sockaddr) rescue IO::WaitWritable IO.select(nil, [socket]) # wait 3-way handshake completion begin # ****************** The problem is here ******************** socket.connect_nonblock(sockaddr) # check connection failure rescue Errno::EISCONN end end socket.write("GET / HTTP/1.0\r\n\r\n") results = socket.read ~~~ The first call to `connect_nonblock` raises `IO::WaitWritable` as expected. But the confirmation call did not raise `Errno::EISCONN`; instead, it returned `0`. Upon source code inspection, 0 was returned from `connect` and is supposed to mean success. ~~~C static VALUE sock_connect_nonblock(VALUE sock, VALUE addr, VALUE ex) { VALUE rai; rb_io_t *fptr; int n; SockAddrStringValueWithAddrinfo(addr, rai); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); rb_io_set_nonblock(fptr); n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)); if (n < 0) { int e = errno; if (e == EINPROGRESS) { if (ex == Qfalse) { return sym_wait_writable; } rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "connect(2) would block"); } if (e == EISCONN) { if (ex == Qfalse) { return INT2FIX(0); } } rsock_syserr_fail_raddrinfo_or_sockaddr(e, "connect(2)", addr, rai); } return INT2FIX(n); } ~~~ I made sure `ex` is `true`, so it is not `return INT2FIX(0);` that get returned but the last statement `return INT2FIX(n);`. Is this the intended behavior? It does surprise me and clearly doesn't explain very well in the document. The example shown implied that the only way to confirm the connection is `Errno::EISCONN`; never mention the return code. -- https://bugs.ruby-lang.org/ Unsubscribe: