unix/stream: repair SO_SNDTIMEO
The send operations are waiting on the peer's socket buffer, but we shall
use our timeout value. Provide a test for that.
Reported by: phk
Reviewed by: asomers
Differential Revision: https://reviews.freebsd.org/D53081
Fixes: d157927807
This commit is contained in:
+18
-2
@@ -1069,6 +1069,21 @@ uipc_stream_sbspace(struct sockbuf *sb)
|
||||
return (min(space, mbspace));
|
||||
}
|
||||
|
||||
/*
|
||||
* UNIX version of generic sbwait() for writes. We wait on peer's receive
|
||||
* buffer, using our timeout.
|
||||
*/
|
||||
static int
|
||||
uipc_stream_sbwait(struct socket *so, sbintime_t timeo)
|
||||
{
|
||||
struct sockbuf *sb = &so->so_rcv;
|
||||
|
||||
SOCK_RECVBUF_LOCK_ASSERT(so);
|
||||
sb->sb_flags |= SB_WAIT;
|
||||
return (msleep_sbt(&sb->sb_acc, SOCK_RECVBUF_MTX(so), PSOCK | PCATCH,
|
||||
"sbwait", timeo, 0, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
uipc_sosend_stream_or_seqpacket(struct socket *so, struct sockaddr *addr,
|
||||
struct uio *uio0, struct mbuf *m, struct mbuf *c, int flags,
|
||||
@@ -1203,7 +1218,8 @@ uipc_sosend_stream_or_seqpacket(struct socket *so, struct sockaddr *addr,
|
||||
error = EWOULDBLOCK;
|
||||
goto out4;
|
||||
}
|
||||
if ((error = sbwait(so2, SO_RCV)) != 0) {
|
||||
if ((error = uipc_stream_sbwait(so2,
|
||||
so->so_snd.sb_timeo)) != 0) {
|
||||
SOCK_RECVBUF_UNLOCK(so2);
|
||||
goto out4;
|
||||
} else
|
||||
@@ -2397,7 +2413,7 @@ uipc_sendfile_wait(struct socket *so, off_t need, int *space)
|
||||
}
|
||||
if (!sockref)
|
||||
soref(so2);
|
||||
error = sbwait(so2, SO_RCV);
|
||||
error = uipc_stream_sbwait(so2, so->so_snd.sb_timeo);
|
||||
if (error == 0 &&
|
||||
__predict_false(sb->sb_state & SBS_CANTRCVMORE))
|
||||
error = EPIPE;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
* Copyright (c) 2018 Alan Somers
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <sys/event.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -490,6 +492,30 @@ ATF_TC_BODY(ourshutdown_kevent, tc)
|
||||
close(sv[1]);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(SO_SNDTIMEO);
|
||||
ATF_TC_BODY(SO_SNDTIMEO, tc)
|
||||
{
|
||||
struct timespec tp1, tp2, rtp, sleep = { .tv_nsec = 100000000 };
|
||||
int sv[2];
|
||||
char buf[10];
|
||||
|
||||
full_socketpair(sv);
|
||||
ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDTIMEO,
|
||||
&(struct timeval){ .tv_usec = sleep.tv_nsec / 1000 },
|
||||
sizeof(struct timeval)));
|
||||
ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp1));
|
||||
ATF_REQUIRE_EQ(-1, send(sv[0], buf, sizeof(buf), 0));
|
||||
ATF_REQUIRE(errno == EAGAIN);
|
||||
ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp2));
|
||||
timespecsub(&tp2, &tp1, &rtp);
|
||||
ATF_REQUIRE(timespeccmp(&rtp, &sleep, >=));
|
||||
ATF_REQUIRE_EQ(sizeof(buf), recv(sv[1], buf, sizeof(buf), 0));
|
||||
ATF_REQUIRE_EQ(sizeof(buf), send(sv[0], buf, sizeof(buf), 0));
|
||||
|
||||
close(sv[0]);
|
||||
close(sv[1]);
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, getpeereid);
|
||||
@@ -506,6 +532,7 @@ ATF_TP_ADD_TCS(tp)
|
||||
ATF_TP_ADD_TC(tp, peershutdown_wakeup_poll);
|
||||
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
|
||||
ATF_TP_ADD_TC(tp, ourshutdown_kevent);
|
||||
ATF_TP_ADD_TC(tp, SO_SNDTIMEO);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user