From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS24940 5.9.0.0/16 X-Spam-Status: No, score=-1.9 required=3.0 tests=AWL,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: spew@80x24.org Received: from 80x24.org (tor-relay.zwiebeltoralf.de [5.9.158.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 6EB1820322 for ; Thu, 12 Nov 2015 09:03:22 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH] socket: Socket#connect_nonblock avoids get_kwarg Date: Thu, 12 Nov 2015 09:03:20 +0000 Message-Id: <20151112090320.18483-1-e@80x24.org> List-Id: Note: this is difficult to benchmark since kernel socket allocations are non-deterministic. --- ext/socket/lib/socket.rb | 48 ++++++++++++++++++++++++++++++++++++- ext/socket/socket.c | 61 +++++++----------------------------------------- 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index 7c66e8f..cd2ba45 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -864,5 +864,51 @@ class Socket < BasicSocket } end + # call-seq: + # socket.connect_nonblock(remote_sockaddr, [options]) => 0 + # + # Requests a connection to be made on the given +remote_sockaddr+ after + # O_NONBLOCK is set for the underlying file descriptor. + # Returns 0 if successful, otherwise an exception is raised. + # + # === Parameter + # # +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object + # + # === Example: + # # 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 + # 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 + # + # Refer to Socket#connect for the exceptions that may be thrown if the call + # to _connect_nonblock_ fails. + # + # Socket#connect_nonblock may raise any error corresponding to connect(2) failure, + # including Errno::EINPROGRESS. + # + # If the exception is Errno::EINPROGRESS, + # it is extended by IO::WaitWritable. + # So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock. + # + # By specifying `exception: false`, the options hash allows you to indicate + # that connect_nonblock should not raise an IO::WaitWritable exception, but + # return the symbol :wait_writable instead. + # + # === See + # # Socket#connect + def connect_nonblock(addr, exception: true) + __connect_nonblock(addr, exception) + end end - diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 779398c..b75ba95 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -439,62 +439,14 @@ sock_connect(VALUE sock, VALUE addr) return INT2FIX(n); } -/* - * call-seq: - * socket.connect_nonblock(remote_sockaddr, [options]) => 0 - * - * Requests a connection to be made on the given +remote_sockaddr+ after - * O_NONBLOCK is set for the underlying file descriptor. - * Returns 0 if successful, otherwise an exception is raised. - * - * === Parameter - * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object - * - * === Example: - * # 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 - * 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 - * - * Refer to Socket#connect for the exceptions that may be thrown if the call - * to _connect_nonblock_ fails. - * - * Socket#connect_nonblock may raise any error corresponding to connect(2) failure, - * including Errno::EINPROGRESS. - * - * If the exception is Errno::EINPROGRESS, - * it is extended by IO::WaitWritable. - * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock. - * - * By specifying `exception: false`, the options hash allows you to indicate - * that connect_nonblock should not raise an IO::WaitWritable exception, but - * return the symbol :wait_writable instead. - * - * === See - * * Socket#connect - */ +/* :nodoc: */ static VALUE -sock_connect_nonblock(int argc, VALUE *argv, VALUE sock) +connect_nb(VALUE sock, VALUE addr, VALUE ex) { - VALUE addr; - VALUE opts = Qnil; VALUE rai; rb_io_t *fptr; int n; - rb_scan_args(argc, argv, "1:", &addr, &opts); SockAddrStringValueWithAddrinfo(addr, rai); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); @@ -502,13 +454,13 @@ sock_connect_nonblock(int argc, VALUE *argv, VALUE sock) n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)); if (n < 0) { if (errno == EINPROGRESS) { - if (rsock_opt_false_p(opts, sym_exception)) { + if (ex == Qfalse) { return sym_wait_writable; } rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block"); } if (errno == EISCONN) { - if (rsock_opt_false_p(opts, sym_exception)) { + if (ex == Qfalse) { return INT2FIX(0); } } @@ -2174,7 +2126,10 @@ Init_socket(void) rb_define_method(rb_cSocket, "initialize", sock_initialize, -1); rb_define_method(rb_cSocket, "connect", sock_connect, 1); - rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, -1); + + /* for ext/socket/lib/socket.rb use only: */ + rb_define_private_method(rb_cSocket, "__connect_nonblock", connect_nb, 2); + rb_define_method(rb_cSocket, "bind", sock_bind, 1); rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1); rb_define_method(rb_cSocket, "accept", sock_accept, 0); -- EW