summaryrefslogtreecommitdiff
path: root/ext/socket/init.c
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2022-09-20 16:10:56 +0200
committerJean Boussier <[email protected]>2023-08-30 10:07:18 +0200
commitbcc905100f1079e191632cfd02319c10af82dac0 (patch)
treee8dbe37eb4de741c51210f65ffaa0336ce579c8a /ext/socket/init.c
parentacedbcb1b4eb6b362f11e783bff53c237d05afc6 (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/socket/init.c')
-rw-r--r--ext/socket/init.c20
1 files changed, 20 insertions, 0 deletions
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) {