diff --git a/ChangeLog b/ChangeLog index 1878b203e0..6ef7ac6fb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Jun 18 00:49:11 2006 Tanaka Akira + + * ext/socket/socket.c (bsock_recv_nonblock): new method + BasicSocket#recv_nonblock. + (udp_recvfrom_nonblock): renamed from ip_recvfrom_nonblock. + IPSocket#recvfrom_nonblock is moved to UDPSocket#recvfrom_nonblock. + (unix_recvfrom_nonblock): removed. UNIXSocket#is removed. + Sat Jun 17 14:53:32 2006 Tanaka Akira * lib/pathname.rb: backport from 1.9. diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 7dea26ad49..80a271baaf 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -605,7 +605,7 @@ s_recvfrom(sock, argc, argv, from) } static VALUE -s_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock, enum sock_recv_type from) +s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) { OpenFile *fptr; VALUE str; @@ -650,17 +650,14 @@ s_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock, enum sock_recv_type from) } rb_obj_taint(str); switch (from) { + case RECV_RECV: + return str; + case RECV_IP: if (alen) /* connection-oriented socket may not return a from result */ addr = ipaddr((struct sockaddr*)buf); break; -#ifdef HAVE_SYS_UN_H - case RECV_UNIX: - addr = unixaddr((struct sockaddr_un*)buf, alen); - break; -#endif - case RECV_SOCKET: addr = rb_str_new(buf, alen); break; @@ -680,6 +677,52 @@ bsock_recv(argc, argv, sock) return s_recvfrom(sock, argc, argv, RECV_RECV); } +/* + * call-seq: + * basicsocket.recv_nonblock(maxlen) => mesg + * basicsocket.recv_nonblock(maxlen, flags) => 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 + * + * === 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 + * IO.select([s]) + * p s.recv_nonblock(10) #=> "aaa" + * + * 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::EAGAIN. + * + * === See + * * Socket#recvfrom + */ + +static VALUE +bsock_recv_nonblock(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return s_recvfrom_nonblock(sock, argc, argv, RECV_RECV); +} + static VALUE bsock_do_not_rev_lookup() { @@ -1609,51 +1652,6 @@ ip_recvfrom(argc, argv, sock) return s_recvfrom(sock, argc, argv, RECV_IP); } -/* - * call-seq: - * ipsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr] - * ipsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr] - * - * Receives up to _maxlen_ bytes from +ipsocket+ 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_inet_addr_, is an array to represent the sender address. - * - * 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 number of bytes to receive from the socket - * * +flags+ - zero or more of the +MSG_+ options - * - * === Example - * require 'socket' - * socket = TCPSocket.new("localhost", "daytime") - * begin - * p socket.recvfrom_nonblock(20) - * rescue Errno::EAGAIN - * IO.select([socket]) - * retry - * end - * socket.close - * - * Refer to Socket#recvfrom for the exceptions that may be thrown if the call - * to _recvfrom_nonblock_ fails. - * - * IPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, - * including Errno::EAGAIN. - * - * === See - * * Socket#recvfrom - */ -static VALUE -ip_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) -{ - return s_recvfrom_nonblock(argc, argv, sock, RECV_IP); -} - static VALUE ip_s_getaddress(obj, host) VALUE obj, host; @@ -1790,6 +1788,52 @@ udp_send(argc, argv, sock) return INT2FIX(n); } +/* + * call-seq: + * udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr] + * udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr] + * + * Receives up to _maxlen_ bytes from +udpsocket+ 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_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 + * + * === 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 + * IO.select([s2]) + * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]] + * + * 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::EAGAIN. + * + * === See + * * Socket#recvfrom + */ +static VALUE +udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) +{ + return s_recvfrom_nonblock(sock, argc, argv, RECV_IP); +} + #ifdef HAVE_SYS_UN_H static VALUE unix_init(sock, path) @@ -1840,51 +1884,6 @@ unix_recvfrom(argc, argv, sock) return s_recvfrom(sock, argc, argv, RECV_UNIX); } -/* - * call-seq: - * unixsocket.recvfrom_nonblock(maxlen) => [mesg, sender_unix_addr] - * unixsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_unix_addr] - * - * Receives up to _maxlen_ bytes from +unixsocket+ 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_unix_addr_, is an array to represent the sender address. - * - * When recvfrom(2) returns 0, UNIXSocket#recvfrom_nonblock returns - * an empty string as data. - * It means EOF for UNIXSocket#recvfrom_nonblock. - * - * === Parameters - * * +maxlen+ - the number of bytes to receive from the socket - * * +flags+ - zero or more of the +MSG_+ options - * - * === Example - * require 'socket' - * socket = UNIXSocket.new("/tmp/sock") - * begin - * p socket.recvfrom_nonblock(20) - * rescue Errno::EAGAIN - * IO.select([socket]) - * retry - * end - * socket.close - * - * Refer to Socket#recvfrom for the exceptions that may be thrown if the call - * to _recvfrom_nonblock_ fails. - * - * IPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, - * including Errno::EAGAIN. - * - * === See - * * Socket#recvfrom - */ -static VALUE -unix_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) -{ - return s_recvfrom_nonblock(argc, argv, sock, RECV_UNIX); -} - #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS) #define FD_PASSING_BY_MSG_CONTROL 1 #else @@ -2884,7 +2883,7 @@ sock_recvfrom(argc, argv, sock) static VALUE sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) { - return s_recvfrom_nonblock(argc, argv, sock, RECV_SOCKET); + return s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET); } /* @@ -3861,13 +3860,13 @@ Init_socket() rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0); rb_define_method(rb_cBasicSocket, "send", bsock_send, -1); rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); + rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1); rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket); rb_define_global_const("IPsocket", rb_cIPSocket); rb_define_method(rb_cIPSocket, "addr", ip_addr, 0); rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, 0); rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1); - rb_define_method(rb_cIPSocket, "recvfrom_nonblock", ip_recvfrom_nonblock, -1); rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1); rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket); @@ -3898,6 +3897,7 @@ Init_socket() 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); #ifdef HAVE_SYS_UN_H rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket); @@ -3907,7 +3907,6 @@ Init_socket() rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0); rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0); rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1); - rb_define_method(rb_cUNIXSocket, "recvfrom_nonblock", unix_recvfrom_nonblock, -1); rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1); rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1); rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1); diff --git a/test/socket/test_nonblock.rb b/test/socket/test_nonblock.rb index 33123fbcc0..07d0004e70 100644 --- a/test/socket/test_nonblock.rb +++ b/test/socket/test_nonblock.rb @@ -71,38 +71,25 @@ class TestNonblockSocket < Test::Unit::TestCase u2.close if u2 end - def bound_unix_socket(klass) - tmpfile = Tempfile.new("testrubysock") - path = tmpfile.path - tmpfile.close(true) - return klass.new(path), path - end - - def test_unix_recvfrom_nonblock - serv, serv_path = bound_unix_socket(UNIXServer) - c = UNIXSocket.new(serv_path) - s = serv.accept - assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.recvfrom_nonblock(100) } - assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { c.recvfrom_nonblock(100) } - s.write "aaa" - IO.select [c] - mesg, unix_addr = c.recvfrom_nonblock(100) + def test_udp_recv_nonblock + u1 = UDPSocket.new + u2 = UDPSocket.new + u1.bind("127.0.0.1", 0) + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recv_nonblock(100) } + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINVAL) { u2.recv_nonblock(100) } + u2.send("aaa", 0, u1.getsockname) + IO.select [u1] + mesg = u1.recv_nonblock(100) assert_equal("aaa", mesg) - assert_equal(2, unix_addr.length) - af, path = unix_addr - if path != "" # connection-oriented socket may not return the peer address. - assert_equal(serv_path, path) - end - s.close - IO.select [c] - mesg, unix_addr = c.recvfrom_nonblock(100) + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recv_nonblock(100) } + u2.send("", 0, u1.getsockname) + IO.select [u1] + mesg = u1.recv_nonblock(100) assert_equal("", mesg) ensure - File.unlink serv_path if serv_path && File.socket?(serv_path) - serv.close if serv - c.close if c - s.close if s && !s.closed? - end if defined?(UNIXSocket) + u1.close if u1 + u2.close if u2 + end def test_socket_recvfrom_nonblock s1 = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) @@ -132,6 +119,20 @@ class TestNonblockSocket < Test::Unit::TestCase serv.close if serv end + def test_tcp_recv_nonblock + c, s = tcp_pair + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { c.recv_nonblock(100) } + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.recv_nonblock(100) } + c.write("abc") + IO.select [s] + assert_equal("a", s.recv_nonblock(1)) + assert_equal("bc", s.recv_nonblock(100)) + assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.recv_nonblock(100) } + ensure + c.close if c + s.close if s + end + def test_read_nonblock c, s = tcp_pair assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { c.read_nonblock(100) } diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb index 80fc3b4f05..008a970234 100644 --- a/test/socket/test_unix.rb +++ b/test/socket/test_unix.rb @@ -101,11 +101,11 @@ class TestUNIXSocket < Test::Unit::TestCase s2.close end - def test_noname_recvfrom_nonblock + def test_noname_recv_nonblock s1, s2 = UNIXSocket.pair s2.write("a") IO.select [s1] - assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom_nonblock(10)) + assert_equal("a", s1.recv_nonblock(10)) ensure s1.close s2.close @@ -123,7 +123,7 @@ class TestUNIXSocket < Test::Unit::TestCase def test_dgram_pair s1, s2 = UNIXSocket.pair(Socket::SOCK_DGRAM) - assert_raise(Errno::EAGAIN) { s1.recvfrom_nonblock(10) } + assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } s2.send("", 0) s2.send("haha", 0) s2.send("", 0) @@ -132,7 +132,7 @@ class TestUNIXSocket < Test::Unit::TestCase assert_equal("haha", s1.recv(10)) assert_equal("", s1.recv(10)) assert_equal("", s1.recv(10)) - assert_raise(Errno::EAGAIN) { s1.recvfrom_nonblock(10) } + assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } ensure s1.close s2.close @@ -140,7 +140,7 @@ class TestUNIXSocket < Test::Unit::TestCase def test_seqpacket_pair s1, s2 = UNIXSocket.pair(Socket::SOCK_SEQPACKET) - assert_raise(Errno::EAGAIN) { s1.recvfrom_nonblock(10) } + assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } s2.send("", 0) s2.send("haha", 0) s2.send("", 0) @@ -149,7 +149,7 @@ class TestUNIXSocket < Test::Unit::TestCase assert_equal("haha", s1.recv(10)) assert_equal("", s1.recv(10)) assert_equal("", s1.recv(10)) - assert_raise(Errno::EAGAIN) { s1.recvfrom_nonblock(10) } + assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } rescue Errno::EPROTONOSUPPORT ensure s1.close if s1