summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--ext/socket/basicsocket.c60
-rw-r--r--ext/socket/init.c13
-rw-r--r--ext/socket/lib/socket.rb171
-rw-r--r--ext/socket/rubysocket.h3
-rw-r--r--ext/socket/socket.c72
-rw-r--r--ext/socket/udpsocket.c63
7 files changed, 213 insertions, 183 deletions
diff --git a/ChangeLog b/ChangeLog
index 774b4b0ce9..17c5cc312c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Tue Nov 17 08:16:09 2015 Eric Wong <e@80x24.org>
+
+ * ext/socket/init.c (rsock_s_recvfrom_nonblock):
+ avoid arg parsing with C API
+ [ruby-core:71439] [Feature #11339]
+ * ext/socket/basicsocket.c (bsock_recv_nonblock):
+ adjust for above change, make private
+ * ext/socket/socket.c (sock_recvfrom_nonblock): ditto
+ * ext/socket/udpsocket.c (udp_recvfrom_nonblock): ditto
+ * ext/socket/lib/socket.rb (BasicSocket#recv_nonblock):
+ new wrapper for private method, move RDoc
+ (Socket#recvfrom_nonblock): ditto
+ (UDPSocket#recvfrom_nonblock): ditto
+
Mon Nov 16 21:27:54 2015 Naohisa Goto <ngotogenome@gmail.com>
* test/dtrace/helper.rb (Dtrace::TestCase#trap_probe): dtrace buffer
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index e5597f0de5..6bf10e8cbb 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -643,59 +643,11 @@ bsock_recv(int argc, VALUE *argv, VALUE sock)
return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
}
-/*
- * call-seq:
- * basicsocket.recv_nonblock(maxlen [, flags [, options ]) => mesg
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The result, _mesg_, is the data received.
- *
- * When recvfrom(2) returns 0, Socket#recv_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * serv = TCPServer.new("127.0.0.1", 0)
- * af, port, host, addr = serv.addr
- * c = TCPSocket.new(addr, port)
- * s = serv.accept
- * c.send "aaa", 0
- * begin # emulate blocking recv.
- * p s.recv_nonblock(10) #=> "aaa"
- * rescue IO::WaitReadable
- * IO.select([s])
- * retry
- * end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recv_nonblock_ fails.
- *
- * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recv_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
-
+/* :nodoc: */
static VALUE
-bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
+bsock_recv_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_RECV);
}
/*
@@ -764,10 +716,14 @@ rsock_init_basicsocket(void)
rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
- rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
+
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cBasicSocket,
+ "__recv_nonblock", bsock_recv_nonblock, 4);
+
rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 1710129519..350ba652e7 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -200,24 +200,19 @@ rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
}
VALUE
-rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
+rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+ VALUE ex, enum sock_recv_type from)
{
rb_io_t *fptr;
- VALUE str;
union_sockaddr buf;
socklen_t alen = (socklen_t)sizeof buf;
- VALUE len, flg;
long buflen;
long slen;
int fd, flags;
VALUE addr = Qnil;
- VALUE opts = Qnil;
socklen_t len0;
- rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
-
- if (flg == Qnil) flags = 0;
- else flags = NUM2INT(flg);
+ flags = NUM2INT(flg);
buflen = NUM2INT(len);
str = rsock_strbuf(str, buflen);
@@ -249,7 +244,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
- if (rsock_opt_false_p(opts, sym_exception))
+ if (ex == Qfalse)
return sym_wait_readable;
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
}
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index d5f66bcd27..6ee89e90d0 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -274,6 +274,56 @@ class BasicSocket < IO
end
addr
end
+
+ # call-seq:
+ # basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
+ #
+ # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The result, _mesg_, is the data received.
+ #
+ # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+ #
+ # === Parameters
+ # * +maxlen+ - the number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ # * +options+ - keyword hash, supporting `exception: false`
+ #
+ # === Example
+ # serv = TCPServer.new("127.0.0.1", 0)
+ # af, port, host, addr = serv.addr
+ # c = TCPSocket.new(addr, port)
+ # s = serv.accept
+ # c.send "aaa", 0
+ # begin # emulate blocking recv.
+ # p s.recv_nonblock(10) #=> "aaa"
+ # rescue IO::WaitReadable
+ # IO.select([s])
+ # retry
+ # end
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recv_nonblock_ fails.
+ #
+ # BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
+ #
+ # By specifying `exception: false`, the options hash allows you to indicate
+ # that recv_nonblock should not raise an IO::WaitWritable exception, but
+ # return the symbol :wait_writable instead.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recv_nonblock(len, flag = 0, str = nil, exception: true)
+ __recv_nonblock(len, flag, str, exception)
+ end
end
class Socket < BasicSocket
@@ -284,6 +334,70 @@ class Socket < BasicSocket
end
end
+ # call-seq:
+ # socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
+ # socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
+ #
+ # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The first element of the results, _mesg_, is the data received.
+ # The second element, _sender_addrinfo_, contains protocol-specific address
+ # information of the sender.
+ #
+ # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+ #
+ # === Parameters
+ # * +maxlen+ - the maximum number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ #
+ # === Example
+ # # In one file, 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)
+ # client, client_addrinfo = socket.accept
+ # begin # emulate blocking recvfrom
+ # pair = client.recvfrom_nonblock(20)
+ # rescue IO::WaitReadable
+ # IO.select([client])
+ # retry
+ # end
+ # data = pair[0].chomp
+ # puts "I only received 20 bytes '#{data}'"
+ # sleep 1
+ # socket.close
+ #
+ # # In another file, 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 "Watch this get cut short!"
+ # socket.close
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recvfrom_nonblock_ fails.
+ #
+ # Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+ __recvfrom_nonblock(len, flag, str, 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])
@@ -868,3 +982,60 @@ class Socket < BasicSocket
end
+class UDPSocket < IPSocket
+
+ # call-seq:
+ # udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
+ #
+ # Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # If _maxlen_ is omitted, its default value is 65536.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The first element of the results, _mesg_, is the data received.
+ # The second element, _sender_inet_addr_, is an array to represent the sender address.
+ #
+ # When recvfrom(2) returns 0,
+ # Socket#recvfrom_nonblock returns an empty string as data.
+ # It means an empty packet.
+ #
+ # === Parameters
+ # * +maxlen+ - the number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ # * +options+ - keyword hash, supporting `exception: false`
+ #
+ # === Example
+ # require 'socket'
+ # s1 = UDPSocket.new
+ # s1.bind("127.0.0.1", 0)
+ # s2 = UDPSocket.new
+ # s2.bind("127.0.0.1", 0)
+ # s2.connect(*s1.addr.values_at(3,1))
+ # s1.connect(*s2.addr.values_at(3,1))
+ # s1.send "aaa", 0
+ # begin # emulate blocking recvfrom
+ # p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
+ # rescue IO::WaitReadable
+ # IO.select([s2])
+ # retry
+ # end
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recvfrom_nonblock_ fails.
+ #
+ # UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+ #
+ # By specifying `exception: false`, the options hash allows you to indicate
+ # that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
+ # return the symbol :wait_writable instead.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+ __recvfrom_nonblock(len, flag, str, exception)
+ end
+end
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 601667d59d..9fa16ec9dc 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -347,7 +347,8 @@ enum sock_recv_type {
RECV_SOCKET /* Socket#recvfrom */
};
-VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
+VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+ VALUE ex, enum sock_recv_type from);
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 779398c88d..1a3320dbe5 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -813,72 +813,11 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock)
return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
}
-/*
- * call-seq:
- * socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
- * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_addrinfo_, contains protocol-specific address
- * information of the sender.
- *
- * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the maximum number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- * # In one file, 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)
- * client, client_addrinfo = socket.accept
- * begin # emulate blocking recvfrom
- * pair = client.recvfrom_nonblock(20)
- * rescue IO::WaitReadable
- * IO.select([client])
- * retry
- * end
- * data = pair[0].chomp
- * puts "I only received 20 bytes '#{data}'"
- * sleep 1
- * socket.close
- *
- * # In another file, 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 "Watch this get cut short!"
- * socket.close
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
static VALUE
-sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+sock_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_SOCKET);
}
/*
@@ -2182,7 +2121,10 @@ Init_socket(void)
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
- rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cSocket,
+ "__recvfrom_nonblock", sock_recvfrom_nonblock, 4);
rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index d55ddfe6bb..7b7b34f04d 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -214,63 +214,11 @@ udp_send(int argc, VALUE *argv, VALUE sock)
return ret;
}
-/*
- * call-seq:
- * udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
- *
- * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * If _maxlen_ is omitted, its default value is 65536.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_inet_addr_, is an array to represent the sender address.
- *
- * When recvfrom(2) returns 0,
- * Socket#recvfrom_nonblock returns an empty string as data.
- * It means an empty packet.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * require 'socket'
- * s1 = UDPSocket.new
- * s1.bind("127.0.0.1", 0)
- * s2 = UDPSocket.new
- * s2.bind("127.0.0.1", 0)
- * s2.connect(*s1.addr.values_at(3,1))
- * s1.connect(*s2.addr.values_at(3,1))
- * s1.send "aaa", 0
- * begin # emulate blocking recvfrom
- * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
- * rescue IO::WaitReadable
- * IO.select([s2])
- * retry
- * end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
static VALUE
-udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
}
void
@@ -287,5 +235,8 @@ rsock_init_udpsocket(void)
rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
- rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cUDPSocket,
+ "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
}