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));
|
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
|
static int
|
||||||
uipc_sosend_stream_or_seqpacket(struct socket *so, struct sockaddr *addr,
|
uipc_sosend_stream_or_seqpacket(struct socket *so, struct sockaddr *addr,
|
||||||
struct uio *uio0, struct mbuf *m, struct mbuf *c, int flags,
|
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;
|
error = EWOULDBLOCK;
|
||||||
goto out4;
|
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);
|
SOCK_RECVBUF_UNLOCK(so2);
|
||||||
goto out4;
|
goto out4;
|
||||||
} else
|
} else
|
||||||
@@ -2397,7 +2413,7 @@ uipc_sendfile_wait(struct socket *so, off_t need, int *space)
|
|||||||
}
|
}
|
||||||
if (!sockref)
|
if (!sockref)
|
||||||
soref(so2);
|
soref(so2);
|
||||||
error = sbwait(so2, SO_RCV);
|
error = uipc_stream_sbwait(so2, so->so_snd.sb_timeo);
|
||||||
if (error == 0 &&
|
if (error == 0 &&
|
||||||
__predict_false(sb->sb_state & SBS_CANTRCVMORE))
|
__predict_false(sb->sb_state & SBS_CANTRCVMORE))
|
||||||
error = EPIPE;
|
error = EPIPE;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*-
|
/*-
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
|
||||||
* Copyright (c) 2018 Alan Somers
|
* Copyright (c) 2018 Alan Somers
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
#include <sys/event.h>
|
#include <sys/event.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -490,6 +492,30 @@ ATF_TC_BODY(ourshutdown_kevent, tc)
|
|||||||
close(sv[1]);
|
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_TCS(tp)
|
||||||
{
|
{
|
||||||
ATF_TP_ADD_TC(tp, getpeereid);
|
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_poll);
|
||||||
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
|
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
|
||||||
ATF_TP_ADD_TC(tp, ourshutdown_kevent);
|
ATF_TP_ADD_TC(tp, ourshutdown_kevent);
|
||||||
|
ATF_TP_ADD_TC(tp, SO_SNDTIMEO);
|
||||||
|
|
||||||
return atf_no_error();
|
return atf_no_error();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user