summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@google.com>2019-07-18 15:39:47 -0700
committergVisor bot <gvisor-bot@google.com>2019-07-18 15:41:04 -0700
commiteefa817cfdb04ff07e7069396f21bd6ba2c89957 (patch)
tree7114a733e361dbf98e2ef1ae075945bfb908107a /test/syscalls/linux
parent163ab5e9bab4f14923433967656d20f169d0f904 (diff)
net/tcp/setockopt: impelment setsockopt(fd, SOL_TCP, TCP_INQ)
PiperOrigin-RevId: 258859507
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/tcp_socket.cc138
1 files changed, 138 insertions, 0 deletions
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc
index 8d77431f2..77aab1e7d 100644
--- a/test/syscalls/linux/tcp_socket.cc
+++ b/test/syscalls/linux/tcp_socket.cc
@@ -16,6 +16,7 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -520,6 +521,143 @@ TEST_P(TcpSocketTest, SetNoDelay) {
EXPECT_EQ(get, kSockOptOff);
}
+#ifndef TCP_INQ
+#define TCP_INQ 36
+#endif
+
+TEST_P(TcpSocketTest, TcpInqSetSockOpt) {
+ char buf[1024];
+ ASSERT_THAT(RetryEINTR(write)(s_, buf, sizeof(buf)),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ // TCP_INQ is disabled by default.
+ int val = -1;
+ socklen_t slen = sizeof(val);
+ EXPECT_THAT(getsockopt(t_, SOL_TCP, TCP_INQ, &val, &slen),
+ SyscallSucceedsWithValue(0));
+ ASSERT_EQ(val, 0);
+
+ // Try to set TCP_INQ.
+ val = 1;
+ EXPECT_THAT(setsockopt(t_, SOL_TCP, TCP_INQ, &val, sizeof(val)),
+ SyscallSucceedsWithValue(0));
+ val = -1;
+ slen = sizeof(val);
+ EXPECT_THAT(getsockopt(t_, SOL_TCP, TCP_INQ, &val, &slen),
+ SyscallSucceedsWithValue(0));
+ ASSERT_EQ(val, 1);
+
+ // Try to unset TCP_INQ.
+ val = 0;
+ EXPECT_THAT(setsockopt(t_, SOL_TCP, TCP_INQ, &val, sizeof(val)),
+ SyscallSucceedsWithValue(0));
+ val = -1;
+ slen = sizeof(val);
+ EXPECT_THAT(getsockopt(t_, SOL_TCP, TCP_INQ, &val, &slen),
+ SyscallSucceedsWithValue(0));
+ ASSERT_EQ(val, 0);
+}
+
+TEST_P(TcpSocketTest, TcpInq) {
+ char buf[1024];
+ // Write more than one TCP segment.
+ int size = sizeof(buf);
+ int kChunk = sizeof(buf) / 4;
+ for (int i = 0; i < size; i += kChunk) {
+ ASSERT_THAT(RetryEINTR(write)(s_, buf, kChunk),
+ SyscallSucceedsWithValue(kChunk));
+ }
+
+ int val = 1;
+ kChunk = sizeof(buf) / 2;
+ EXPECT_THAT(setsockopt(t_, SOL_TCP, TCP_INQ, &val, sizeof(val)),
+ SyscallSucceedsWithValue(0));
+
+ // Wait when all data will be in the received queue.
+ while (true) {
+ ASSERT_THAT(ioctl(t_, TIOCINQ, &size), SyscallSucceeds());
+ if (size == sizeof(buf)) {
+ break;
+ }
+ usleep(10000);
+ }
+
+ struct msghdr msg = {};
+ std::vector<char> control(CMSG_SPACE(sizeof(int)));
+ size = sizeof(buf);
+ struct iovec iov;
+ for (int i = 0; size != 0; i += kChunk) {
+ msg.msg_control = &control[0];
+ msg.msg_controllen = control.size();
+
+ iov.iov_base = buf;
+ iov.iov_len = kChunk;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ ASSERT_THAT(RetryEINTR(recvmsg)(t_, &msg, 0),
+ SyscallSucceedsWithValue(kChunk));
+ size -= kChunk;
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ ASSERT_NE(cmsg, nullptr);
+ ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int)));
+ ASSERT_EQ(cmsg->cmsg_level, SOL_TCP);
+ ASSERT_EQ(cmsg->cmsg_type, TCP_INQ);
+
+ int inq = 0;
+ memcpy(&inq, CMSG_DATA(cmsg), sizeof(int));
+ ASSERT_EQ(inq, size);
+ }
+}
+
+TEST_P(TcpSocketTest, TcpSCMPriority) {
+ char buf[1024];
+ ASSERT_THAT(RetryEINTR(write)(s_, buf, sizeof(buf)),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ int val = 1;
+ EXPECT_THAT(setsockopt(t_, SOL_TCP, TCP_INQ, &val, sizeof(val)),
+ SyscallSucceedsWithValue(0));
+ EXPECT_THAT(setsockopt(t_, SOL_SOCKET, SO_TIMESTAMP, &val, sizeof(val)),
+ SyscallSucceedsWithValue(0));
+
+ struct msghdr msg = {};
+ std::vector<char> control(
+ CMSG_SPACE(sizeof(struct timeval) + CMSG_SPACE(sizeof(int))));
+ struct iovec iov;
+ msg.msg_control = &control[0];
+ msg.msg_controllen = control.size();
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ ASSERT_THAT(RetryEINTR(recvmsg)(t_, &msg, 0),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ ASSERT_NE(cmsg, nullptr);
+ // TODO(b/78348848): SO_TIMESTAMP isn't implemented for TCP sockets.
+ if (!IsRunningOnGvisor() || cmsg->cmsg_level == SOL_SOCKET) {
+ ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET);
+ ASSERT_EQ(cmsg->cmsg_type, SO_TIMESTAMP);
+ ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(struct timeval)));
+
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ ASSERT_NE(cmsg, nullptr);
+ }
+ ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int)));
+ ASSERT_EQ(cmsg->cmsg_level, SOL_TCP);
+ ASSERT_EQ(cmsg->cmsg_type, TCP_INQ);
+
+ int inq = 0;
+ memcpy(&inq, CMSG_DATA(cmsg), sizeof(int));
+ ASSERT_EQ(inq, 0);
+
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ ASSERT_EQ(cmsg, nullptr);
+}
+
INSTANTIATE_TEST_SUITE_P(AllInetTests, TcpSocketTest,
::testing::Values(AF_INET, AF_INET6));