diff options
author | Jean Boussier <jean.boussier@gmail.com> | 2022-09-20 16:10:56 +0200 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2023-08-30 10:07:18 +0200 |
commit | bcc905100f1079e191632cfd02319c10af82dac0 (patch) | |
tree | e8dbe37eb4de741c51210f65ffaa0336ce579c8a /ext | |
parent | acedbcb1b4eb6b362f11e783bff53c237d05afc6 (diff) |
BasicSocket#recv* return `nil` rather than an empty packet
[Bug #19012]
man recvmsg(2) states:
> Return Value
> These calls return the number of bytes received, or -1 if an error occurred.
> The return value will be 0 when the peer has performed an orderly shutdown.
Not too sure how one is supposed to make the difference between a packet of
size 0 and a closed connection.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/6407
Diffstat (limited to 'ext')
-rw-r--r-- | ext/socket/ancdata.c | 4 | ||||
-rw-r--r-- | ext/socket/init.c | 20 | ||||
-rw-r--r-- | ext/socket/rubysocket.h | 2 |
3 files changed, 26 insertions, 0 deletions
diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c index 7406177de2..6ef040b692 100644 --- a/ext/socket/ancdata.c +++ b/ext/socket/ancdata.c @@ -1555,6 +1555,10 @@ bsock_recvmsg_internal(VALUE sock, ss = rb_recvmsg(fptr->fd, &mh, flags); + if (ss == 0 && !rsock_is_dgram(fptr)) { + return Qnil; + } + if (ss == -1) { int e; if (!nonblock && rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) { diff --git a/ext/socket/init.c b/ext/socket/init.c index 557d4374a5..e9dc6f8483 100644 --- a/ext/socket/init.c +++ b/ext/socket/init.c @@ -116,6 +116,7 @@ recvfrom_blocking(void *data) ssize_t ret; ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), arg->length, arg->flags, &arg->buf.addr, &arg->alen); + if (ret != -1 && len0 < arg->alen) arg->alen = len0; @@ -147,6 +148,18 @@ recvfrom_locktmp(VALUE v) return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd); } +int +rsock_is_dgram(rb_io_t *fptr) +{ + int socktype; + socklen_t optlen = (socklen_t)sizeof(socktype); + int ret = getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen); + if (ret == -1) { + rb_sys_fail("getsockopt(SO_TYPE)"); + } + return socktype == SOCK_DGRAM; +} + VALUE rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from) { @@ -187,6 +200,9 @@ rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from) slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp, (VALUE)&arg); + if (slen == 0 && !rsock_is_dgram(fptr)) { + return Qnil; + } if (slen >= 0) break; if (!rb_io_maybe_wait_readable(errno, socket, RUBY_IO_TIMEOUT_DEFAULT)) @@ -259,6 +275,10 @@ rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, if (slen != -1 && len0 < alen) alen = len0; + if (slen == 0 && !rsock_is_dgram(fptr)) { + return Qnil; + } + if (slen < 0) { int e = errno; switch (e) { diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 5f803ba0da..7c5739808d 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -459,6 +459,8 @@ VALUE rsock_write_nonblock(VALUE sock, VALUE buf, VALUE ex); void rsock_make_fd_nonblock(int fd); +int rsock_is_dgram(rb_io_t *fptr); + #if !defined HAVE_INET_NTOP && ! defined _WIN32 const char *inet_ntop(int, const void *, char *, size_t); #elif defined __MINGW32__ |