Skip to content

Commit b05f153

Browse files
glebiuscperciva
authored andcommitted
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. Approved by: re (cperciva) Reported by: phk Reviewed by: asomers Differential Revision: https://reviews.freebsd.org/D53081 Fixes: d157927 (cherry picked from commit ead7219) (cherry picked from commit bbfaff2)
1 parent 8d2dcf9 commit b05f153

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

sys/kern/uipc_usrreq.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,21 @@ uipc_stream_sbspace(struct sockbuf *sb)
10691069
return (min(space, mbspace));
10701070
}
10711071

1072+
/*
1073+
* UNIX version of generic sbwait() for writes. We wait on peer's receive
1074+
* buffer, using our timeout.
1075+
*/
1076+
static int
1077+
uipc_stream_sbwait(struct socket *so, sbintime_t timeo)
1078+
{
1079+
struct sockbuf *sb = &so->so_rcv;
1080+
1081+
SOCK_RECVBUF_LOCK_ASSERT(so);
1082+
sb->sb_flags |= SB_WAIT;
1083+
return (msleep_sbt(&sb->sb_acc, SOCK_RECVBUF_MTX(so), PSOCK | PCATCH,
1084+
"sbwait", timeo, 0, 0));
1085+
}
1086+
10721087
static int
10731088
uipc_sosend_stream_or_seqpacket(struct socket *so, struct sockaddr *addr,
10741089
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,
12031218
error = EWOULDBLOCK;
12041219
goto out4;
12051220
}
1206-
if ((error = sbwait(so2, SO_RCV)) != 0) {
1221+
if ((error = uipc_stream_sbwait(so2,
1222+
so->so_snd.sb_timeo)) != 0) {
12071223
SOCK_RECVBUF_UNLOCK(so2);
12081224
goto out4;
12091225
} else
@@ -2397,7 +2413,7 @@ uipc_sendfile_wait(struct socket *so, off_t need, int *space)
23972413
}
23982414
if (!sockref)
23992415
soref(so2);
2400-
error = sbwait(so2, SO_RCV);
2416+
error = uipc_stream_sbwait(so2, so->so_snd.sb_timeo);
24012417
if (error == 0 &&
24022418
__predict_false(sb->sb_state & SBS_CANTRCVMORE))
24032419
error = EPIPE;

tests/sys/kern/unix_stream.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*-
22
* SPDX-License-Identifier: BSD-2-Clause
33
*
4+
* Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
45
* Copyright (c) 2018 Alan Somers
56
*
67
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +31,7 @@
3031
#include <sys/event.h>
3132
#include <sys/select.h>
3233
#include <sys/sysctl.h>
34+
#include <sys/time.h>
3335
#include <sys/un.h>
3436
#include <errno.h>
3537
#include <fcntl.h>
@@ -490,6 +492,30 @@ ATF_TC_BODY(ourshutdown_kevent, tc)
490492
close(sv[1]);
491493
}
492494

495+
ATF_TC_WITHOUT_HEAD(SO_SNDTIMEO);
496+
ATF_TC_BODY(SO_SNDTIMEO, tc)
497+
{
498+
struct timespec tp1, tp2, rtp, sleep = { .tv_nsec = 100000000 };
499+
int sv[2];
500+
char buf[10];
501+
502+
full_socketpair(sv);
503+
ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDTIMEO,
504+
&(struct timeval){ .tv_usec = sleep.tv_nsec / 1000 },
505+
sizeof(struct timeval)));
506+
ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp1));
507+
ATF_REQUIRE_EQ(-1, send(sv[0], buf, sizeof(buf), 0));
508+
ATF_REQUIRE(errno == EAGAIN);
509+
ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC_PRECISE, &tp2));
510+
timespecsub(&tp2, &tp1, &rtp);
511+
ATF_REQUIRE(timespeccmp(&rtp, &sleep, >=));
512+
ATF_REQUIRE_EQ(sizeof(buf), recv(sv[1], buf, sizeof(buf), 0));
513+
ATF_REQUIRE_EQ(sizeof(buf), send(sv[0], buf, sizeof(buf), 0));
514+
515+
close(sv[0]);
516+
close(sv[1]);
517+
}
518+
493519
ATF_TP_ADD_TCS(tp)
494520
{
495521
ATF_TP_ADD_TC(tp, getpeereid);
@@ -506,6 +532,7 @@ ATF_TP_ADD_TCS(tp)
506532
ATF_TP_ADD_TC(tp, peershutdown_wakeup_poll);
507533
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
508534
ATF_TP_ADD_TC(tp, ourshutdown_kevent);
535+
ATF_TP_ADD_TC(tp, SO_SNDTIMEO);
509536

510537
return atf_no_error();
511538
}

0 commit comments

Comments
 (0)