From: "midnight (Sarun R)" Date: 2022-05-19T19:22:57+00:00 Subject: [ruby-core:108626] [Ruby master Bug#18791] Unexpected behavior of Socket#connect_nonblock Issue #18791 has been reported by midnight (Sarun R). ---------------------------------------- Bug #18791: Unexpected behavior of Socket#connect_nonblock https://bugs.ruby-lang.org/issues/18791 * Author: midnight (Sarun R) * Status: Open * 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: