Feature #11139 » socket-support-accept-sock_nonblock-true-false-v2.patch
ext/socket/ancdata.c | ||
---|---|---|
goto retry;
|
||
}
|
||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||
if (rsock_opt_false_p(opts, sym_exception)) {
|
||
if (rsock_opt_eq(opts, sym_exception, Qfalse)) {
|
||
return sym_wait_writable;
|
||
}
|
||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE,
|
||
... | ... | |
goto retry;
|
||
}
|
||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||
if (rsock_opt_false_p(vopts, sym_exception)) {
|
||
if (rsock_opt_eq(vopts, sym_exception, Qfalse)) {
|
||
return sym_wait_readable;
|
||
}
|
||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
|
ext/socket/init.c | ||
---|---|---|
#endif
|
||
int rsock_do_not_reverse_lookup = 1;
|
||
static VALUE sym_exception, sym_wait_readable;
|
||
static VALUE sym_exception, sym_wait_readable, sym_sock_nonblock;
|
||
void
|
||
rsock_raise_socket_error(const char *reason, int error)
|
||
... | ... | |
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||
case EWOULDBLOCK:
|
||
#endif
|
||
if (rsock_opt_false_p(opts, sym_exception))
|
||
if (rsock_opt_eq(opts, sym_exception, Qfalse))
|
||
return sym_wait_readable;
|
||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
|
||
}
|
||
... | ... | |
static int
|
||
cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len,
|
||
int nonblock)
|
||
int sock_nonblock)
|
||
{
|
||
int ret;
|
||
socklen_t len0 = 0;
|
||
... | ... | |
flags |= SOCK_CLOEXEC;
|
||
#endif
|
||
#ifdef SOCK_NONBLOCK
|
||
if (nonblock) {
|
||
if (sock_nonblock) {
|
||
flags |= SOCK_NONBLOCK;
|
||
}
|
||
#endif
|
||
... | ... | |
if (ret <= 2)
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
#ifndef SOCK_NONBLOCK
|
||
if (nonblock) {
|
||
if (sock_nonblock) {
|
||
make_fd_nonblock(ret);
|
||
}
|
||
#endif
|
||
... | ... | |
if (ret == -1) return -1;
|
||
if (address_len && len0 < *address_len) *address_len = len0;
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
if (nonblock) {
|
||
if (sock_nonblock) {
|
||
make_fd_nonblock(ret);
|
||
}
|
||
return ret;
|
||
... | ... | |
struct sockaddr *sockaddr, socklen_t *len)
|
||
{
|
||
int fd2;
|
||
VALUE opts = Qnil;
|
||
VALUE opts;
|
||
int sock_nonblock = 1;
|
||
rb_scan_args(argc, argv, "0:", &opts);
|
||
if (rsock_opt_eq(opts, sym_sock_nonblock, Qfalse))
|
||
sock_nonblock = 0;
|
||
rb_io_set_nonblock(fptr);
|
||
fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len, 1);
|
||
fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len,
|
||
sock_nonblock);
|
||
if (fd2 < 0) {
|
||
switch (errno) {
|
||
case EAGAIN:
|
||
... | ... | |
#if defined EPROTO
|
||
case EPROTO:
|
||
#endif
|
||
if (rsock_opt_false_p(opts, sym_exception))
|
||
if (rsock_opt_eq(opts, sym_exception, Qfalse))
|
||
return sym_wait_readable;
|
||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
|
||
}
|
||
... | ... | |
struct accept_arg {
|
||
int fd;
|
||
int sock_nonblock;
|
||
struct sockaddr *sockaddr;
|
||
socklen_t *len;
|
||
};
|
||
... | ... | |
accept_blocking(void *data)
|
||
{
|
||
struct accept_arg *arg = data;
|
||
return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len, 0);
|
||
return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len,
|
||
arg->sock_nonblock);
|
||
}
|
||
VALUE
|
||
rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
|
||
rsock_s_accept(int argc, VALUE *argv, VALUE klass, int fd,
|
||
struct sockaddr *sockaddr, socklen_t *len)
|
||
{
|
||
int fd2;
|
||
int retry = 0;
|
||
struct accept_arg arg;
|
||
VALUE opts;
|
||
arg.fd = fd;
|
||
arg.sock_nonblock = 0;
|
||
arg.sockaddr = sockaddr;
|
||
arg.len = len;
|
||
rb_scan_args(argc, argv, "0:", &opts);
|
||
if (!NIL_P(opts) &&
|
||
rb_hash_lookup2(opts, sym_sock_nonblock, Qundef) == Qtrue) {
|
||
arg.sock_nonblock = 1;
|
||
}
|
||
retry:
|
||
rsock_maybe_wait_fd(fd);
|
||
fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
|
||
... | ... | |
#undef rb_intern
|
||
sym_exception = ID2SYM(rb_intern("exception"));
|
||
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
|
||
sym_sock_nonblock = ID2SYM(rb_intern("sock_nonblock"));
|
||
}
|
ext/socket/rubysocket.h | ||
---|---|---|
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(int argc, VALUE *argv, 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_sock_listen(VALUE sock, VALUE log);
|
||
... | ... | |
#endif
|
||
static inline int
|
||
rsock_opt_false_p(VALUE opt, VALUE sym)
|
||
rsock_opt_eq(VALUE opt, VALUE sym, VALUE exp)
|
||
{
|
||
if (!NIL_P(opt) && Qfalse == rb_hash_lookup2(opt, sym, Qundef))
|
||
if (!NIL_P(opt) && exp == rb_hash_lookup2(opt, sym, Qundef))
|
||
return 1;
|
||
return 0;
|
||
}
|
ext/socket/socket.c | ||
---|---|---|
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 (rsock_opt_eq(opts, sym_exception, 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 (rsock_opt_eq(opts, sym_exception, Qfalse)) {
|
||
return INT2FIX(0);
|
||
}
|
||
}
|
||
... | ... | |
*
|
||
*/
|
||
static VALUE
|
||
sock_accept(VALUE sock)
|
||
sock_accept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
VALUE sock2;
|
||
... | ... | |
socklen_t len = (socklen_t)sizeof buf;
|
||
GetOpenFile(sock, fptr);
|
||
sock2 = rsock_s_accept(rb_cSocket,fptr->fd,&buf.addr,&len);
|
||
sock2 = rsock_s_accept(argc, argv, rb_cSocket, fptr->fd, &buf.addr, &len);
|
||
return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
|
||
}
|
||
... | ... | |
* * Socket#accept
|
||
*/
|
||
static VALUE
|
||
sock_sysaccept(VALUE sock)
|
||
sock_sysaccept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
VALUE sock2;
|
||
... | ... | |
socklen_t len = (socklen_t)sizeof buf;
|
||
GetOpenFile(sock, fptr);
|
||
sock2 = rsock_s_accept(0,fptr->fd,&buf.addr,&len);
|
||
sock2 = rsock_s_accept(argc, argv, 0, fptr->fd, &buf.addr, &len);
|
||
return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
|
||
}
|
||
... | ... | |
rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, -1);
|
||
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", sock_accept, -1);
|
||
rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, -1);
|
||
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
|
||
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, -1);
|
||
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
|
||
rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
|
ext/socket/tcpserver.c | ||
---|---|---|
*
|
||
*/
|
||
static VALUE
|
||
tcp_accept(VALUE sock)
|
||
tcp_accept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
union_sockaddr from;
|
||
... | ... | |
GetOpenFile(sock, fptr);
|
||
fromlen = (socklen_t)sizeof(from);
|
||
return rsock_s_accept(rb_cTCPSocket, fptr->fd, &from.addr, &fromlen);
|
||
return rsock_s_accept(argc, argv, rb_cTCPSocket,
|
||
fptr->fd, &from.addr, &fromlen);
|
||
}
|
||
/*
|
||
... | ... | |
*
|
||
*/
|
||
static VALUE
|
||
tcp_sysaccept(VALUE sock)
|
||
tcp_sysaccept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
union_sockaddr from;
|
||
... | ... | |
GetOpenFile(sock, fptr);
|
||
fromlen = (socklen_t)sizeof(from);
|
||
return rsock_s_accept(0, fptr->fd, &from.addr, &fromlen);
|
||
return rsock_s_accept(argc, argv, 0, fptr->fd, &from.addr, &fromlen);
|
||
}
|
||
void
|
||
... | ... | |
*
|
||
*/
|
||
rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
|
||
rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
|
||
rb_define_method(rb_cTCPServer, "accept", tcp_accept, -1);
|
||
rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, -1);
|
||
rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
|
||
rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, -1);
|
||
rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
|
||
rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
|
||
}
|
ext/socket/unixserver.c | ||
---|---|---|
*
|
||
*/
|
||
static VALUE
|
||
unix_accept(VALUE sock)
|
||
unix_accept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
struct sockaddr_un from;
|
||
... | ... | |
GetOpenFile(sock, fptr);
|
||
fromlen = (socklen_t)sizeof(struct sockaddr_un);
|
||
return rsock_s_accept(rb_cUNIXSocket, fptr->fd,
|
||
return rsock_s_accept(argc, argv, rb_cUNIXSocket, fptr->fd,
|
||
(struct sockaddr*)&from, &fromlen);
|
||
}
|
||
... | ... | |
*
|
||
*/
|
||
static VALUE
|
||
unix_sysaccept(VALUE sock)
|
||
unix_sysaccept(int argc, VALUE *argv, VALUE sock)
|
||
{
|
||
rb_io_t *fptr;
|
||
struct sockaddr_un from;
|
||
... | ... | |
GetOpenFile(sock, fptr);
|
||
fromlen = (socklen_t)sizeof(struct sockaddr_un);
|
||
return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
|
||
return rsock_s_accept(argc, argv, 0, fptr->fd,
|
||
(struct sockaddr*)&from, &fromlen);
|
||
}
|
||
#endif
|
||
... | ... | |
*/
|
||
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", unix_accept, -1);
|
||
rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, -1);
|
||
rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
|
||
rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, -1);
|
||
rb_define_method(rb_cUNIXServer, "listen", rsock_sock_listen, 1); /* in socket.c */
|
||
#endif
|
||
}
|
test/socket/test_nonblock.rb | ||
---|---|---|
s, sockaddr = serv.accept_nonblock
|
||
end
|
||
assert_equal(Socket.unpack_sockaddr_in(c.getsockname), Socket.unpack_sockaddr_in(sockaddr))
|
||
if s.respond_to?(:nonblock?)
|
||
assert_predicate(s, :nonblock?, 'accepted socket is non-blocking')
|
||
assert_predicate(s, :nonblock?, 'default behavior should be non-blocking')
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
b = Socket.new(:INET, :STREAM)
|
||
b.connect(serv.getsockname)
|
||
serv.wait_readable
|
||
a, _ = serv.accept_nonblock(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
a.close if a
|
||
b.close if b
|
||
end
|
||
end
|
||
ensure
|
||
serv.close if serv
|
||
... | ... | |
s.close if s && !s.closed?
|
||
end
|
||
def test_accept_sock_nonblock
|
||
serv = Socket.new(:INET, :STREAM)
|
||
serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
|
||
serv.listen(5)
|
||
begin
|
||
s, _ = serv.accept_nonblock
|
||
rescue Errno::EWOULDBLOCK
|
||
assert_kind_of(IO::WaitReadable, $!)
|
||
end
|
||
ensure
|
||
serv.close if serv && !serv.closed?
|
||
s.close if s && !s.closed?
|
||
end
|
||
def test_accept_blocking_sock_nonblock
|
||
serv = Socket.new(:INET, :STREAM)
|
||
serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
|
||
serv.listen(5)
|
||
begin
|
||
b = Socket.new(:INET, :STREAM)
|
||
b.connect(serv.getsockname)
|
||
a, _ = serv.accept
|
||
refute_predicate a, :nonblock?
|
||
ensure
|
||
a.close
|
||
b.close
|
||
end
|
||
begin
|
||
b = Socket.new(:INET, :STREAM)
|
||
b.connect(serv.getsockname)
|
||
a, _ = serv.sysaccept
|
||
a = Socket.for_fd(a)
|
||
refute_predicate a, :nonblock?
|
||
ensure
|
||
a.close
|
||
b.close
|
||
end
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
b = Socket.new(:INET, :STREAM)
|
||
b.connect(serv.getsockname)
|
||
serv.wait_readable
|
||
a, _ = serv.accept(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
a.close if a
|
||
b.close if b
|
||
end
|
||
begin
|
||
b = Socket.new(:INET, :STREAM)
|
||
b.connect(serv.getsockname)
|
||
serv.wait_readable
|
||
a, _ = serv.sysaccept(sock_nonblock: nb)
|
||
a = Socket.for_fd(a)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
a.close if a
|
||
b.close if b
|
||
end
|
||
end
|
||
ensure
|
||
serv.close
|
||
end
|
||
end if defined?(Socket)
|
test/socket/test_tcp.rb | ||
---|---|---|
rescue LoadError
|
||
end
|
||
require "io/wait"
|
||
require "io/nonblock"
|
||
class TestSocket_TCPSocket < Test::Unit::TestCase
|
||
def test_initialize_failure
|
||
... | ... | |
assert_raise(IO::WaitReadable) { svr.accept_nonblock }
|
||
assert_equal :wait_readable, svr.accept_nonblock(exception: false)
|
||
assert_raise(IO::WaitReadable) { svr.accept_nonblock(exception: true) }
|
||
addr = svr.addr
|
||
host, port = addr[3], addr[1]
|
||
begin
|
||
c = TCPSocket.new(host, port)
|
||
svr.wait_readable
|
||
a = svr.accept_nonblock
|
||
assert_predicate a, :nonblock?, 'default behavior'
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
c = TCPSocket.new(host, port)
|
||
svr.wait_readable
|
||
a = svr.accept_nonblock(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
end
|
||
}
|
||
end
|
||
def test_accept_sock_nonblock
|
||
TCPServer.open("localhost", 0) do |svr|
|
||
addr = svr.addr
|
||
host, port = addr[3], addr[1]
|
||
begin
|
||
c = TCPSocket.new(host, port)
|
||
a = svr.accept
|
||
refute_predicate a, :nonblock?, 'default behavior'
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
c = TCPSocket.new(host, port)
|
||
a = svr.accept(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end if defined?(TCPSocket)
|
test/socket/test_unix.rb | ||
---|---|---|
require "tmpdir"
|
||
require "thread"
|
||
require "io/nonblock"
|
||
require "io/wait"
|
||
class TestSocket_UNIXSocket < Test::Unit::TestCase
|
||
def test_fd_passing
|
||
... | ... | |
assert_raise(IO::WaitReadable) { serv.accept_nonblock }
|
||
assert_raise(IO::WaitReadable) { serv.accept_nonblock(exception: true) }
|
||
assert_equal :wait_readable, serv.accept_nonblock(exception: false)
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
serv.wait_readable
|
||
a = serv.accept_nonblock
|
||
assert_predicate a, :nonblock?, 'default behavior'
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
serv.wait_readable
|
||
a = serv.accept_nonblock(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
end
|
||
}
|
||
end
|
||
def test_accept_sock_nonblock
|
||
bound_unix_socket(UNIXServer) do |serv, path|
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
a = serv.accept
|
||
refute_predicate a, :nonblock?, 'default behavior'
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
a = serv.sysaccept
|
||
a = UNIXSocket.for_fd(a)
|
||
refute_predicate a, :nonblock?, 'default behavior'
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
[ true, false ].each do |nb|
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
a = serv.accept(sock_nonblock: nb)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
begin
|
||
c = UNIXSocket.new(path)
|
||
a = serv.sysaccept(sock_nonblock: nb)
|
||
a = UNIXSocket.for_fd(a)
|
||
assert_equal nb, a.nonblock?
|
||
ensure
|
||
c.close if c
|
||
a.close if a
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM
|
||
-
|
- « Previous
- 1
- 2
- Next »