mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support getsockopt for SO_ACCEPTCONN.
The SO_ACCEPTCONN option is used only on getsockopt(). When this option is specified, getsockopt() indicates whether socket listening is enabled for the socket. A value of zero indicates that socket listening is disabled; non-zero that it is enabled. PiperOrigin-RevId: 338703206
This commit is contained in:
committed by
gVisor bot
parent
dad08229b8
commit
39e9b3bb8a
@@ -1244,6 +1244,18 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
|
||||
vP := primitive.Int32(boolToInt32(v))
|
||||
return &vP, nil
|
||||
|
||||
case linux.SO_ACCEPTCONN:
|
||||
if outLen < sizeOfInt32 {
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
v, err := ep.GetSockOptBool(tcpip.AcceptConnOption)
|
||||
if err != nil {
|
||||
return nil, syserr.TranslateNetstackError(err)
|
||||
}
|
||||
vP := primitive.Int32(boolToInt32(v))
|
||||
return &vP, nil
|
||||
|
||||
default:
|
||||
socket.GetSockOptEmitUnimplementedEvent(t, name)
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ func (e *baseEndpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
|
||||
|
||||
func (e *baseEndpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
switch opt {
|
||||
case tcpip.KeepaliveEnabledOption:
|
||||
case tcpip.KeepaliveEnabledOption, tcpip.AcceptConnOption:
|
||||
return false, nil
|
||||
|
||||
case tcpip.PasscredOption:
|
||||
|
||||
@@ -763,6 +763,10 @@ const (
|
||||
// endpoint that all packets being written have an IP header and the
|
||||
// endpoint should not attach an IP header.
|
||||
IPHdrIncludedOption
|
||||
|
||||
// AcceptConnOption is used by GetSockOptBool to indicate if the
|
||||
// socket is a listening socket.
|
||||
AcceptConnOption
|
||||
)
|
||||
|
||||
// SockOptInt represents socket options which values have the int type.
|
||||
|
||||
@@ -378,7 +378,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
|
||||
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
|
||||
func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
switch opt {
|
||||
case tcpip.KeepaliveEnabledOption:
|
||||
case tcpip.KeepaliveEnabledOption, tcpip.AcceptConnOption:
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
|
||||
@@ -389,7 +389,12 @@ func (ep *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
|
||||
|
||||
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
|
||||
func (*endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
return false, tcpip.ErrNotSupported
|
||||
switch opt {
|
||||
case tcpip.AcceptConnOption:
|
||||
return false, nil
|
||||
default:
|
||||
return false, tcpip.ErrNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
|
||||
|
||||
@@ -601,7 +601,7 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
|
||||
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
|
||||
func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
switch opt {
|
||||
case tcpip.KeepaliveEnabledOption:
|
||||
case tcpip.KeepaliveEnabledOption, tcpip.AcceptConnOption:
|
||||
return false, nil
|
||||
|
||||
case tcpip.IPHdrIncludedOption:
|
||||
|
||||
@@ -1999,6 +1999,12 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
case tcpip.MulticastLoopOption:
|
||||
return true, nil
|
||||
|
||||
case tcpip.AcceptConnOption:
|
||||
e.LockUser()
|
||||
defer e.UnlockUser()
|
||||
|
||||
return e.EndpointState() == StateListen, nil
|
||||
|
||||
default:
|
||||
return false, tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
|
||||
@@ -895,6 +895,9 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
|
||||
return v, nil
|
||||
|
||||
case tcpip.AcceptConnOption:
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
return false, tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
|
||||
@@ -664,6 +664,17 @@ TEST_P(RawPacketTest, SetAndGetSocketLinger) {
|
||||
EXPECT_EQ(0, memcmp(&sl, &got_linger, length));
|
||||
}
|
||||
|
||||
TEST_P(RawPacketTest, GetSocketAcceptConn) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
|
||||
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(getsockopt(s_, SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(AllInetTests, RawPacketTest,
|
||||
::testing::Values(ETH_P_IP, ETH_P_ALL));
|
||||
|
||||
|
||||
@@ -438,6 +438,19 @@ TEST_F(RawSocketICMPTest, SetAndGetSocketLinger) {
|
||||
EXPECT_EQ(0, memcmp(&sl, &got_linger, length));
|
||||
}
|
||||
|
||||
// Test getsockopt for SO_ACCEPTCONN.
|
||||
TEST_F(RawSocketICMPTest, GetSocketAcceptConn) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
|
||||
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(getsockopt(s_, SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
|
||||
void RawSocketICMPTest::ExpectICMPSuccess(const struct icmphdr& icmp) {
|
||||
// We're going to receive both the echo request and reply, but the order is
|
||||
// indeterminate.
|
||||
|
||||
@@ -472,5 +472,19 @@ TEST_P(UDPSocketPairTest, SetAndGetSocketLinger) {
|
||||
EXPECT_EQ(0, memcmp(&sl, &got_linger, length));
|
||||
}
|
||||
|
||||
// Test getsockopt for SO_ACCEPTCONN on udp socket.
|
||||
TEST_P(UDPSocketPairTest, GetSocketAcceptConn) {
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(
|
||||
getsockopt(sockets->first_fd(), SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
@@ -121,6 +121,19 @@ TEST_P(StreamUnixSocketPairTest, SetAndGetSocketLinger) {
|
||||
EXPECT_EQ(0, memcmp(&got_linger, &sl, length));
|
||||
}
|
||||
|
||||
TEST_P(StreamUnixSocketPairTest, GetSocketAcceptConn) {
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(
|
||||
getsockopt(sockets->first_fd(), SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AllUnixDomainSockets, StreamUnixSocketPairTest,
|
||||
::testing::ValuesIn(IncludeReversals(VecCat<SocketPairKind>(
|
||||
|
||||
@@ -1725,6 +1725,63 @@ TEST_P(SimpleTcpSocketTest, CloseNonConnectedLingerOption) {
|
||||
ASSERT_LT((end_time - start_time), absl::Seconds(kLingerTimeout));
|
||||
}
|
||||
|
||||
// Tests that SO_ACCEPTCONN returns non zero value for listening sockets.
|
||||
TEST_P(TcpSocketTest, GetSocketAcceptConnListener) {
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(getsockopt(listener_, SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceeds());
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 1);
|
||||
}
|
||||
|
||||
// Tests that SO_ACCEPTCONN returns zero value for not listening sockets.
|
||||
TEST_P(TcpSocketTest, GetSocketAcceptConnNonListener) {
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(getsockopt(s_, SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceeds());
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
|
||||
ASSERT_THAT(getsockopt(t_, SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceeds());
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
|
||||
TEST_P(SimpleTcpSocketTest, GetSocketAcceptConnWithShutdown) {
|
||||
// TODO(b/171345701): Fix the TCP state for listening socket on shutdown.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
FileDescriptor s =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
|
||||
|
||||
// Initialize address to the loopback one.
|
||||
sockaddr_storage addr =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(GetParam()));
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
// Bind to some port then start listening.
|
||||
ASSERT_THAT(bind(s.get(), reinterpret_cast<struct sockaddr*>(&addr), addrlen),
|
||||
SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(listen(s.get(), SOMAXCONN), SyscallSucceeds());
|
||||
|
||||
int got = -1;
|
||||
socklen_t length = sizeof(got);
|
||||
ASSERT_THAT(getsockopt(s.get(), SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceeds());
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 1);
|
||||
|
||||
EXPECT_THAT(shutdown(s.get(), SHUT_RD), SyscallSucceeds());
|
||||
ASSERT_THAT(getsockopt(s.get(), SOL_SOCKET, SO_ACCEPTCONN, &got, &length),
|
||||
SyscallSucceeds());
|
||||
ASSERT_EQ(length, sizeof(got));
|
||||
EXPECT_EQ(got, 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AllInetTests, SimpleTcpSocketTest,
|
||||
::testing::Values(AF_INET, AF_INET6));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user