summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--ext/socket/init.c10
-rw-r--r--ext/socket/lib/socket.rb140
-rw-r--r--ext/socket/rubysocket.h3
-rw-r--r--ext/socket/socket.c66
-rw-r--r--ext/socket/tcpserver.c48
-rw-r--r--ext/socket/unixserver.c47
7 files changed, 179 insertions, 148 deletions
diff --git a/ChangeLog b/ChangeLog
index 151188cc81..ac9061aa2d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Tue Nov 17 08:36:34 2015 Eric Wong <e@80x24.org>
+
+ * ext/socket/init.c (rsock_s_accept_nonblock): avoid parsing args
+ [ruby-core:71439] [Feature #11339]
+ * ext/socket/rubysocket.h: adjust prototype
+ * ext/socket/socket.c (sock_accept_nonblock): make private
+ * ext/socket/tcpserver.c (tcp_accept_nonblock): ditto
+ * ext/socket/unixserver.c (unix_accept_nonblock): ditto
+ * ext/socket/lib/socket.rb (Socket#accept_nonblock):
+ implement as wrapper, move RDoc
+ (TCPServer#accept_nonblock): ditto
+ (UNIXServer#accept_nonblock): ditto
+
Tue Nov 17 08:25:57 2015 Eric Wong <e@80x24.org>
* ext/socket/socket.c (sock_connect_nonblock):
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 350ba652e7..45070d5d12 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -29,7 +29,7 @@ VALUE rb_cSOCKSSocket;
#endif
int rsock_do_not_reverse_lookup = 1;
-static VALUE sym_exception, sym_wait_readable;
+static VALUE sym_wait_readable;
void
rsock_raise_socket_error(const char *reason, int error)
@@ -544,13 +544,10 @@ cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len,
}
VALUE
-rsock_s_accept_nonblock(int argc, VALUE *argv, VALUE klass, rb_io_t *fptr,
+rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
struct sockaddr *sockaddr, socklen_t *len)
{
int fd2;
- VALUE opts = Qnil;
-
- rb_scan_args(argc, argv, "0:", &opts);
rb_io_set_nonblock(fptr);
fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len, 1);
@@ -564,7 +561,7 @@ rsock_s_accept_nonblock(int argc, VALUE *argv, VALUE klass, rb_io_t *fptr,
#if defined EPROTO
case EPROTO:
#endif
- if (rsock_opt_false_p(opts, sym_exception))
+ if (ex == Qfalse)
return sym_wait_readable;
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
}
@@ -673,6 +670,5 @@ rsock_init_socket_init(void)
rsock_init_socket_constants();
#undef rb_intern
- sym_exception = ID2SYM(rb_intern("exception"));
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
}
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 86da09e997..fed1d43e34 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -398,6 +398,63 @@ class Socket < BasicSocket
__recvfrom_nonblock(len, flag, str, exception)
end
+ # call-seq:
+ # socket.accept_nonblock([options]) => [client_socket, client_addrinfo]
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an array containing the accepted socket
+ # for the incoming connection, _client_socket_,
+ # and an Addrinfo, _client_addrinfo_.
+ #
+ # === Example
+ # # In one script, start this first
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.bind(sockaddr)
+ # socket.listen(5)
+ # begin # emulate blocking accept
+ # client_socket, client_addrinfo = socket.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([socket])
+ # retry
+ # end
+ # puts "The client said, '#{client_socket.readline.chomp}'"
+ # client_socket.puts "Hello from script one!"
+ # socket.close
+ #
+ # # In another script, start this second
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.connect(sockaddr)
+ # socket.puts "Hello from script 2."
+ # puts "The server said, '#{socket.readline.chomp}'"
+ # socket.close
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to _accept_nonblock_ fails.
+ #
+ # Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying `exception: false`, the options hash allows you to indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol :wait_readable instead.
+ #
+ # === See
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
+
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
@@ -1086,3 +1143,86 @@ class UDPSocket < IPSocket
__recvfrom_nonblock(len, flag, str, exception)
end
end
+
+class TCPServer < TCPSocket
+
+ # call-seq:
+ # tcpserver.accept_nonblock([options]) => tcpsocket
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an accepted TCPSocket for the incoming connection.
+ #
+ # === Example
+ # require 'socket'
+ # serv = TCPServer.new(2202)
+ # begin # emulate blocking accept
+ # sock = serv.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([serv])
+ # retry
+ # end
+ # # sock is an accepted socket.
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to TCPServer#accept_nonblock fails.
+ #
+ # TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying `exception: false`, the options hash allows you to indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol :wait_readable instead.
+ #
+ # === See
+ # * TCPServer#accept
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
+end
+
+class UNIXServer < UNIXSocket
+ # call-seq:
+ # unixserver.accept_nonblock([options]) => unixsocket
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an accepted UNIXSocket for the incoming connection.
+ #
+ # === Example
+ # require 'socket'
+ # serv = UNIXServer.new("/tmp/sock")
+ # begin # emulate blocking accept
+ # sock = serv.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([serv])
+ # retry
+ # end
+ # # sock is an accepted socket.
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to UNIXServer#accept_nonblock fails.
+ #
+ # UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying `exception: false`, the options hash allows you to indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol :wait_readable instead.
+ #
+ # === See
+ # * UNIXServer#accept
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
+end
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 9fa16ec9dc..d39de0ab1a 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -354,7 +354,8 @@ VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type fr
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
-VALUE rsock_s_accept_nonblock(int argc, VALUE *argv, VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len);
+VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
+ struct sockaddr *sockaddr, socklen_t *len);
VALUE rsock_sock_listen(VALUE sock, VALUE log);
VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data);
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index a410625537..cc5cbe10d5 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -800,63 +800,9 @@ sock_accept(VALUE sock)
return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}
-/*
- * call-seq:
- * socket.accept_nonblock([options]) => [client_socket, client_addrinfo]
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an array containing the accepted socket
- * for the incoming connection, _client_socket_,
- * and an Addrinfo, _client_addrinfo_.
- *
- * === Example
- * # In one script, start this first
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.bind(sockaddr)
- * socket.listen(5)
- * begin # emulate blocking accept
- * client_socket, client_addrinfo = socket.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([socket])
- * retry
- * end
- * puts "The client said, '#{client_socket.readline.chomp}'"
- * client_socket.puts "Hello from script one!"
- * socket.close
- *
- * # In another script, start this second
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.connect(sockaddr)
- * socket.puts "Hello from script 2."
- * puts "The server said, '#{socket.readline.chomp}'"
- * socket.close
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to _accept_nonblock_ fails.
- *
- * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that accept_nonblock should not raise an IO::WaitReadable exception, but
- * return the symbol :wait_readable instead.
- *
- * === See
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-sock_accept_nonblock(int argc, VALUE *argv, VALUE sock)
+sock_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
VALUE sock2;
@@ -865,7 +811,7 @@ sock_accept_nonblock(int argc, VALUE *argv, VALUE sock)
socklen_t len = (socklen_t)sizeof buf;
GetOpenFile(sock, fptr);
- sock2 = rsock_s_accept_nonblock(argc, argv, rb_cSocket, fptr, addr, &len);
+ sock2 = rsock_s_accept_nonblock(rb_cSocket, ex, fptr, addr, &len);
if (SYMBOL_P(sock2)) /* :wait_readable */
return sock2;
@@ -2073,7 +2019,11 @@ Init_socket(void)
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);
- rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, -1);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cSocket,
+ "__accept_nonblock", sock_accept_nonblock, 1);
+
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c
index a38faf8368..1bbb31adcf 100644
--- a/ext/socket/tcpserver.c
+++ b/ext/socket/tcpserver.c
@@ -64,53 +64,16 @@ tcp_accept(VALUE sock)
return rsock_s_accept(rb_cTCPSocket, fptr->fd, &from.addr, &fromlen);
}
-/*
- * call-seq:
- * tcpserver.accept_nonblock([options]) => tcpsocket
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an accepted TCPSocket for the incoming connection.
- *
- * === Example
- * require 'socket'
- * serv = TCPServer.new(2202)
- * begin # emulate blocking accept
- * sock = serv.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([serv])
- * retry
- * end
- * # sock is an accepted socket.
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to TCPServer#accept_nonblock fails.
- *
- * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that accept_nonblock should not raise an IO::WaitReadable exception, but
- * return the symbol :wait_readable instead.
- *
- * === See
- * * TCPServer#accept
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-tcp_accept_nonblock(int argc, VALUE *argv, VALUE sock)
+tcp_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
union_sockaddr from;
- socklen_t fromlen;
+ socklen_t len = (socklen_t)sizeof(from);
GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept_nonblock(argc, argv, rb_cTCPSocket, fptr, &from.addr, &fromlen);
+ return rsock_s_accept_nonblock(rb_cTCPSocket, ex, fptr, &from.addr, &len);
}
/*
@@ -175,7 +138,8 @@ rsock_init_tcpserver(void)
*/
rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
- rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, -1);
+ rb_define_private_method(rb_cTCPServer,
+ "__accept_nonblock", tcp_accept_nonblock, 1);
rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
diff --git a/ext/socket/unixserver.c b/ext/socket/unixserver.c
index 532d951c93..799dcffb00 100644
--- a/ext/socket/unixserver.c
+++ b/ext/socket/unixserver.c
@@ -57,45 +57,9 @@ unix_accept(VALUE sock)
(struct sockaddr*)&from, &fromlen);
}
-/*
- * call-seq:
- * unixserver.accept_nonblock([options]) => unixsocket
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an accepted UNIXSocket for the incoming connection.
- *
- * === Example
- * require 'socket'
- * serv = UNIXServer.new("/tmp/sock")
- * begin # emulate blocking accept
- * sock = serv.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([serv])
- * retry
- * end
- * # sock is an accepted socket.
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to UNIXServer#accept_nonblock fails.
- *
- * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that accept_nonblock should not raise an IO::WaitReadable exception, but
- * return the symbol :wait_readable instead.
- *
- * === See
- * * UNIXServer#accept
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-unix_accept_nonblock(int argc, VALUE *argv, VALUE sock)
+unix_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
struct sockaddr_un from;
@@ -103,7 +67,7 @@ unix_accept_nonblock(int argc, VALUE *argv, VALUE sock)
GetOpenFile(sock, fptr);
fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept_nonblock(argc, argv, rb_cUNIXSocket, fptr,
+ return rsock_s_accept_nonblock(rb_cUNIXSocket, ex, fptr,
(struct sockaddr *)&from, &fromlen);
}
@@ -152,7 +116,10 @@ rsock_init_unixserver(void)
rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1);
rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
- rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, -1);
+
+ rb_define_private_method(rb_cUNIXServer,
+ "__accept_nonblock", unix_accept_nonblock, 1);
+
rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
rb_define_method(rb_cUNIXServer, "listen", rsock_sock_listen, 1); /* in socket.c */
#endif