1 // Copyright 2022 The gRPC Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/grpc.h>
16 #include <sys/socket.h>
17 #include <unistd.h>
18
19 #include <memory>
20
21 #include "absl/status/status.h"
22 #include "gtest/gtest.h"
23 #include "src/core/lib/iomgr/port.h"
24
25 // IWYU pragma: no_include <arpa/inet.h>
26
27 // This test won't work except with posix sockets enabled
28 #ifdef GRPC_POSIX_SOCKET_UTILS_COMMON
29
30 #include <grpc/support/alloc.h>
31 #include <netinet/in.h>
32 #include <netinet/ip.h>
33
34 #include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h"
35 #include "src/core/lib/iomgr/socket_mutator.h"
36 #include "src/core/util/useful.h"
37
38 namespace grpc_event_engine {
39 namespace experimental {
40
41 namespace {
42
43 struct test_socket_mutator {
44 grpc_socket_mutator base;
45 int option_value;
46 };
47
MutateFd(int fd,grpc_socket_mutator * mutator)48 bool MutateFd(int fd, grpc_socket_mutator* mutator) {
49 int newval;
50 socklen_t intlen = sizeof(newval);
51 struct test_socket_mutator* m =
52 reinterpret_cast<struct test_socket_mutator*>(mutator);
53
54 if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &m->option_value,
55 sizeof(m->option_value))) {
56 return false;
57 }
58 if (0 != getsockopt(fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
59 return false;
60 }
61 if (newval != m->option_value) {
62 return false;
63 }
64 return true;
65 }
66
MutateFd2(const grpc_mutate_socket_info * info,grpc_socket_mutator * mutator)67 bool MutateFd2(const grpc_mutate_socket_info* info,
68 grpc_socket_mutator* mutator) {
69 int newval;
70 socklen_t intlen = sizeof(newval);
71 struct test_socket_mutator* m =
72 reinterpret_cast<struct test_socket_mutator*>(mutator);
73
74 if (0 != setsockopt(info->fd, IPPROTO_IP, IP_TOS, &m->option_value,
75 sizeof(m->option_value))) {
76 return false;
77 }
78 if (0 != getsockopt(info->fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
79 return false;
80 }
81 if (newval != m->option_value) {
82 return false;
83 }
84 return true;
85 }
86
DestroyTestMutator(grpc_socket_mutator * mutator)87 void DestroyTestMutator(grpc_socket_mutator* mutator) {
88 struct test_socket_mutator* m =
89 reinterpret_cast<struct test_socket_mutator*>(mutator);
90 gpr_free(m);
91 }
92
CompareTestMutator(grpc_socket_mutator * a,grpc_socket_mutator * b)93 int CompareTestMutator(grpc_socket_mutator* a, grpc_socket_mutator* b) {
94 struct test_socket_mutator* ma =
95 reinterpret_cast<struct test_socket_mutator*>(a);
96 struct test_socket_mutator* mb =
97 reinterpret_cast<struct test_socket_mutator*>(b);
98 return grpc_core::QsortCompare(ma->option_value, mb->option_value);
99 }
100
101 const grpc_socket_mutator_vtable mutator_vtable = {MutateFd, CompareTestMutator,
102 DestroyTestMutator, nullptr};
103
104 const grpc_socket_mutator_vtable mutator_vtable2 = {
105 nullptr, CompareTestMutator, DestroyTestMutator, MutateFd2};
106
107 } // namespace
108
TEST(TcpPosixSocketUtilsTest,SocketMutatorTest)109 TEST(TcpPosixSocketUtilsTest, SocketMutatorTest) {
110 auto test_with_vtable = [](const grpc_socket_mutator_vtable* vtable) {
111 int sock = socket(PF_INET, SOCK_STREAM, 0);
112 if (sock < 0) {
113 // Try ipv6
114 sock = socket(AF_INET6, SOCK_STREAM, 0);
115 }
116 EXPECT_GT(sock, 0);
117 PosixSocketWrapper posix_sock(sock);
118 struct test_socket_mutator mutator;
119 grpc_socket_mutator_init(&mutator.base, vtable);
120
121 mutator.option_value = IPTOS_LOWDELAY;
122 EXPECT_TRUE(
123 posix_sock
124 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
125 reinterpret_cast<grpc_socket_mutator*>(&mutator))
126 .ok());
127 mutator.option_value = IPTOS_THROUGHPUT;
128 EXPECT_TRUE(
129 posix_sock
130 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
131 reinterpret_cast<grpc_socket_mutator*>(&mutator))
132 .ok());
133
134 mutator.option_value = IPTOS_RELIABILITY;
135 EXPECT_TRUE(
136 posix_sock
137 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
138 reinterpret_cast<grpc_socket_mutator*>(&mutator))
139 .ok());
140
141 mutator.option_value = -1;
142 EXPECT_FALSE(
143 posix_sock
144 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
145 reinterpret_cast<grpc_socket_mutator*>(&mutator))
146 .ok());
147 close(sock);
148 };
149 test_with_vtable(&mutator_vtable);
150 test_with_vtable(&mutator_vtable2);
151 }
152
TEST(TcpPosixSocketUtilsTest,SocketOptionsTest)153 TEST(TcpPosixSocketUtilsTest, SocketOptionsTest) {
154 int sock = socket(PF_INET, SOCK_STREAM, 0);
155 if (sock < 0) {
156 // Try ipv6
157 sock = socket(AF_INET6, SOCK_STREAM, 0);
158 }
159 EXPECT_GT(sock, 0);
160 PosixSocketWrapper posix_sock(sock);
161 EXPECT_TRUE(posix_sock.SetSocketNonBlocking(1).ok());
162 EXPECT_TRUE(posix_sock.SetSocketNonBlocking(0).ok());
163 EXPECT_TRUE(posix_sock.SetSocketCloexec(1).ok());
164 EXPECT_TRUE(posix_sock.SetSocketCloexec(0).ok());
165 EXPECT_TRUE(posix_sock.SetSocketReuseAddr(1).ok());
166 EXPECT_TRUE(posix_sock.SetSocketReuseAddr(0).ok());
167 EXPECT_TRUE(posix_sock.SetSocketLowLatency(1).ok());
168 EXPECT_TRUE(posix_sock.SetSocketLowLatency(0).ok());
169 close(sock);
170 }
171
172 } // namespace experimental
173 } // namespace grpc_event_engine
174
main(int argc,char ** argv)175 int main(int argc, char** argv) {
176 ::testing::InitGoogleTest(&argc, argv);
177 return RUN_ALL_TESTS();
178 }
179
180 #else // GRPC_POSIX_SOCKET_UTILS_COMMON
181
main(int argc,char ** argv)182 int main(int argc, char** argv) { return 0; }
183
184 #endif // GRPC_POSIX_SOCKET_UTILS_COMMON
185