diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-03-19 11:40:38 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-03-19 11:40:38 +0000 |
commit | c4049f4cb6d27ffdfe9f15f4a9ddc5a48271ecf3 (patch) | |
tree | 98df695950d4ad9be608b21479593d4825e293d9 /ext | |
parent | b7800329d3070a4fb9f9dbdbe8b411c5f628f942 (diff) | |
download | ruby-c4049f4cb6d27ffdfe9f15f4a9ddc5a48271ecf3.tar.gz |
* io.c (rb_mWaitReadable): defined.
(rb_mWaitWritable): defined.
(io_getpartial): extend IO::WaitReadable on EWOULDBLOCK and EAGAIN.
(rb_io_write_nonblock): extend IO::WaitWritable on EWOULDBLOCK and
EAGAIN.
* error.c (make_errno_exc): extracted from rb_sys_fail.
(rb_mod_sys_fail): new function.
* include/ruby/ruby.h (rb_mod_sys_fail): declared.
(rb_mWaitReadable): declared.
(rb_mWaitWritable): declared.
* ext/socket/init.c (rsock_s_recvfrom_nonblock): extend
IO::WaitReadable on EWOULDBLOCK and EAGAIN.
(rsock_s_accept_nonblock): extend IO::WaitReadable on EWOULDBLOCK,
EAGAIN, ECONNABORTED and EPROTO.
* ext/socket/socket.c (sock_connect_nonblock): extend IO::WaitWritable
on EINPROGRESS.
* ext/socket/ancdata.c (bsock_sendmsg_internal): extend
IO::WaitWritable on EWOULDBLOCK and EAGAIN.
(bsock_recvmsg_internal): extend IO::WaitReadable on EWOULDBLOCK and
EAGAIN.
* ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): raise SSLError
extended by IO::WaitReadable/IO::WaitWritable on
SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE.
* ext/openssl/ossl.c (ossl_make_error): extracted from ossl_raise.
(ossl_exc_new): new function.
* ext/openssl/ossl.h (ossl_exc_new): declared.
* lib/net/protocol.rb (rbuf_fill): rescue IO::WaitReadable and
IO::WaitWritable.
[ruby-core:22539], [ruby-dev:38140]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23006 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r-- | ext/openssl/ossl.c | 31 | ||||
-rw-r--r-- | ext/openssl/ossl.h | 1 | ||||
-rw-r--r-- | ext/openssl/ossl_ssl.c | 10 | ||||
-rw-r--r-- | ext/socket/ancdata.c | 8 | ||||
-rw-r--r-- | ext/socket/basicsocket.c | 12 | ||||
-rw-r--r-- | ext/socket/init.c | 4 | ||||
-rw-r--r-- | ext/socket/socket.c | 20 | ||||
-rw-r--r-- | ext/socket/tcpserver.c | 6 | ||||
-rw-r--r-- | ext/socket/udpsocket.c | 12 | ||||
-rw-r--r-- | ext/socket/unixserver.c | 6 |
10 files changed, 84 insertions, 26 deletions
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 28696cabe2..d4a2dc1276 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -272,10 +272,9 @@ ossl_to_der_if_possible(VALUE obj) /* * Errors */ -void -ossl_raise(VALUE exc, const char *fmt, ...) +static VALUE +ossl_make_error(VALUE exc, const char *fmt, va_list args) { - va_list args; char buf[BUFSIZ]; const char *msg; long e; @@ -287,9 +286,7 @@ ossl_raise(VALUE exc, const char *fmt, ...) e = ERR_peek_error(); #endif if (fmt) { - va_start(args, fmt); len = vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); } if (len < BUFSIZ && e) { if (dOSSL == Qtrue) /* FULL INFO */ @@ -306,7 +303,29 @@ ossl_raise(VALUE exc, const char *fmt, ...) ERR_clear_error(); if(len > BUFSIZ) len = strlen(buf); - rb_exc_raise(rb_exc_new(exc, buf, len)); + return rb_exc_new(exc, buf, len); +} + +void +ossl_raise(VALUE exc, const char *fmt, ...) +{ + va_list args; + VALUE err; + va_start(args, fmt); + err = ossl_make_error(exc, fmt, args); + va_end(args); + rb_exc_raise(err); +} + +VALUE +ossl_exc_new(VALUE exc, const char *fmt, ...) +{ + va_list args; + VALUE err; + va_start(args, fmt); + err = ossl_make_error(exc, fmt, args); + va_end(args); + return err; } /* diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index e40c93b608..9ac1525085 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -135,6 +135,7 @@ int ossl_pem_passwd_cb(char *, int, int, void *); */ #define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) NORETURN(void ossl_raise(VALUE, const char *, ...)); +VALUE ossl_exc_new(VALUE, const char *, ...); /* * Verify callback diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 767f81e54e..61b30d3afb 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1114,15 +1114,17 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) rb_eof_error(); case SSL_ERROR_WANT_WRITE: if (nonblock) { - errno = EWOULDBLOCK; - rb_sys_fail("SSL_ERROR_WANT_WRITE"); + VALUE exc = ossl_exc_new(eSSLError, "write would block"); + rb_extend_object(exc, rb_mWaitWritable); + rb_exc_raise(exc); } rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: if (nonblock) { - errno = EWOULDBLOCK; - rb_sys_fail("SSL_ERROR_WANT_READ"); + VALUE exc = ossl_exc_new(eSSLError, "read would block"); + rb_extend_object(exc, rb_mWaitReadable); + rb_exc_raise(exc); } rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c index 34a5da317d..b50959c847 100644 --- a/ext/socket/ancdata.c +++ b/ext/socket/ancdata.c @@ -1279,8 +1279,8 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) } if (ss == -1) { - if (nonblock && errno == EWOULDBLOCK) - rb_sys_fail("sendmsg(2) WANT_WRITE"); + if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) + rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block"); rb_sys_fail("sendmsg(2)"); } @@ -1564,8 +1564,8 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) } if (ss == -1) { - if (nonblock && errno == EWOULDBLOCK) - rb_sys_fail("recvmsg(2) WANT_READ"); + if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) + rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block"); #if defined(HAVE_ST_MSG_CONTROL) if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) { /* diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c index a8ab3906e1..78e675c0d3 100644 --- a/ext/socket/basicsocket.c +++ b/ext/socket/basicsocket.c @@ -623,8 +623,12 @@ bsock_recv(int argc, VALUE *argv, VALUE sock) * c = TCPSocket.new(addr, port) * s = serv.accept * c.send "aaa", 0 - * IO.select([s]) # emulate blocking recv. - * p s.recv_nonblock(10) #=> "aaa" + * 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. @@ -632,6 +636,10 @@ bsock_recv(int argc, VALUE *argv, VALUE sock) * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EWOULDBLOCK. * + * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, + * it is extended by IO::WaitReadable. + * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock. + * * === See * * Socket#recvfrom */ diff --git a/ext/socket/init.c b/ext/socket/init.c index 5830f50982..81237536c9 100644 --- a/ext/socket/init.c +++ b/ext/socket/init.c @@ -200,7 +200,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif - rb_sys_fail("recvfrom(2) WANT_READ"); + rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block"); } rb_sys_fail("recvfrom(2)"); } @@ -470,7 +470,7 @@ rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, s #if defined EPROTO case EPROTO: #endif - rb_sys_fail("accept(2) WANT_READ"); + rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block"); } rb_sys_fail("accept(2)"); } diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 00f3525f13..8b3d681d08 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -280,7 +280,7 @@ sock_connect(VALUE sock, VALUE addr) * sockaddr = Socket.sockaddr_in(80, 'www.google.com') * begin # emulate blocking connect * socket.connect_nonblock(sockaddr) - * rescue Errno::EINPROGRESS + * rescue IO::WaitWritable * IO.select(nil, [socket]) # wait 3-way handshake completion * begin * socket.connect_nonblock(sockaddr) # check connection failure @@ -296,6 +296,10 @@ sock_connect(VALUE sock, VALUE addr) * 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. + * * === See * * Socket#connect */ @@ -312,7 +316,7 @@ sock_connect_nonblock(VALUE sock, VALUE addr) n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr)); if (n < 0) { if (errno == EINPROGRESS) - rb_sys_fail("connect(2) WANT_WRITE"); + rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block"); rb_sys_fail("connect(2)"); } @@ -638,7 +642,7 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock) * client, client_sockaddr = socket.accept * begin # emulate blocking recvfrom * pair = client.recvfrom_nonblock(20) - * rescue Errno::EAGAIN, Errno::EWOULDBLOCK + * rescue IO::WaitReadable * IO.select([client]) * retry * end @@ -662,6 +666,10 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock) * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EWOULDBLOCK. * + * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, + * it is extended by IO::WaitReadable. + * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock. + * * === See * * Socket#recvfrom */ @@ -720,7 +728,7 @@ sock_accept(VALUE sock) * socket.listen(5) * begin # emulate blocking accept * client_socket, client_sockaddr = socket.accept_nonblock - * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR + * rescue IO::WaitReadable, Errno::EINTR * IO.select([socket]) * retry * end @@ -743,6 +751,10 @@ sock_accept(VALUE sock) * * Socket#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EWOULDBLOCK. + * + * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, 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. * * === See * * Socket#accept diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c index 1f03642f61..59cd7dd3cc 100644 --- a/ext/socket/tcpserver.c +++ b/ext/socket/tcpserver.c @@ -69,7 +69,7 @@ tcp_accept(VALUE sock) * serv = TCPServer.new(2202) * begin # emulate blocking accept * sock = serv.accept_nonblock - * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR + * rescue IO::WaitReadable, Errno::EINTR * IO.select([serv]) * retry * end @@ -80,6 +80,10 @@ tcp_accept(VALUE sock) * * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EWOULDBLOCK. + * + * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED, Errno::EPROTO, + * it is extended by IO::WaitReadable. + * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock. * * === See * * TCPServer#accept diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c index 2463c8325f..ae1f70eb10 100644 --- a/ext/socket/udpsocket.c +++ b/ext/socket/udpsocket.c @@ -218,8 +218,12 @@ udp_send(int argc, VALUE *argv, VALUE sock) * s2.connect(*s1.addr.values_at(3,1)) * s1.connect(*s2.addr.values_at(3,1)) * s1.send "aaa", 0 - * IO.select([s2]) # emulate blocking recvfrom - * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]] + * 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. @@ -227,6 +231,10 @@ udp_send(int argc, VALUE *argv, VALUE sock) * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EWOULDBLOCK. * + * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, + * it is extended by IO::WaitReadable. + * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock. + * * === See * * Socket#recvfrom */ diff --git a/ext/socket/unixserver.c b/ext/socket/unixserver.c index ec8988d624..fa41cba02a 100644 --- a/ext/socket/unixserver.c +++ b/ext/socket/unixserver.c @@ -70,7 +70,7 @@ unix_accept(VALUE sock) * serv = UNIXServer.new("/tmp/sock") * begin # emulate blocking accept * sock = serv.accept_nonblock - * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR + * rescue IO::WaitReadable, Errno::EINTR * IO.select([serv]) * retry * end @@ -81,6 +81,10 @@ unix_accept(VALUE sock) * * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EWOULDBLOCK. + * + * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, 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. * * === See * * UNIXServer#accept |