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 <sys/socket.h>
16 #include <unistd.h>
17
18 #include <memory>
19
20 #include "absl/status/status.h"
21 #include "gtest/gtest.h"
22
23 #include <grpc/grpc.h>
24
25 #include "src/core/lib/iomgr/port.h"
26
27 // IWYU pragma: no_include <arpa/inet.h>
28
29 // This test won't work except with posix sockets enabled
30 #ifdef GRPC_POSIX_SOCKET_UTILS_COMMON
31
32 #include <netinet/in.h>
33 #include <netinet/ip.h>
34
35 #include <grpc/support/alloc.h>
36
37 #include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h"
38 #include "src/core/lib/gpr/useful.h"
39 #include "src/core/lib/iomgr/socket_mutator.h"
40
41 namespace grpc_event_engine {
42 namespace experimental {
43
44 namespace {
45
46 struct test_socket_mutator {
47 grpc_socket_mutator base;
48 int option_value;
49 };
50
MutateFd(int fd,grpc_socket_mutator * mutator)51 bool MutateFd(int fd, grpc_socket_mutator* mutator) {
52 int newval;
53 socklen_t intlen = sizeof(newval);
54 struct test_socket_mutator* m =
55 reinterpret_cast<struct test_socket_mutator*>(mutator);
56
57 if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &m->option_value,
58 sizeof(m->option_value))) {
59 return false;
60 }
61 if (0 != getsockopt(fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
62 return false;
63 }
64 if (newval != m->option_value) {
65 return false;
66 }
67 return true;
68 }
69
MutateFd2(const grpc_mutate_socket_info * info,grpc_socket_mutator * mutator)70 bool MutateFd2(const grpc_mutate_socket_info* info,
71 grpc_socket_mutator* mutator) {
72 int newval;
73 socklen_t intlen = sizeof(newval);
74 struct test_socket_mutator* m =
75 reinterpret_cast<struct test_socket_mutator*>(mutator);
76
77 if (0 != setsockopt(info->fd, IPPROTO_IP, IP_TOS, &m->option_value,
78 sizeof(m->option_value))) {
79 return false;
80 }
81 if (0 != getsockopt(info->fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
82 return false;
83 }
84 if (newval != m->option_value) {
85 return false;
86 }
87 return true;
88 }
89
DestroyTestMutator(grpc_socket_mutator * mutator)90 void DestroyTestMutator(grpc_socket_mutator* mutator) {
91 struct test_socket_mutator* m =
92 reinterpret_cast<struct test_socket_mutator*>(mutator);
93 gpr_free(m);
94 }
95
CompareTestMutator(grpc_socket_mutator * a,grpc_socket_mutator * b)96 int CompareTestMutator(grpc_socket_mutator* a, grpc_socket_mutator* b) {
97 struct test_socket_mutator* ma =
98 reinterpret_cast<struct test_socket_mutator*>(a);
99 struct test_socket_mutator* mb =
100 reinterpret_cast<struct test_socket_mutator*>(b);
101 return grpc_core::QsortCompare(ma->option_value, mb->option_value);
102 }
103
104 const grpc_socket_mutator_vtable mutator_vtable = {MutateFd, CompareTestMutator,
105 DestroyTestMutator, nullptr};
106
107 const grpc_socket_mutator_vtable mutator_vtable2 = {
108 nullptr, CompareTestMutator, DestroyTestMutator, MutateFd2};
109
110 } // namespace
111
TEST(TcpPosixSocketUtilsTest,SocketMutatorTest)112 TEST(TcpPosixSocketUtilsTest, SocketMutatorTest) {
113 auto test_with_vtable = [](const grpc_socket_mutator_vtable* vtable) {
114 int sock = socket(PF_INET, SOCK_STREAM, 0);
115 if (sock < 0) {
116 // Try ipv6
117 sock = socket(AF_INET6, SOCK_STREAM, 0);
118 }
119 EXPECT_GT(sock, 0);
120 PosixSocketWrapper posix_sock(sock);
121 struct test_socket_mutator mutator;
122 grpc_socket_mutator_init(&mutator.base, vtable);
123
124 mutator.option_value = IPTOS_LOWDELAY;
125 EXPECT_TRUE(
126 posix_sock
127 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
128 reinterpret_cast<grpc_socket_mutator*>(&mutator))
129 .ok());
130 mutator.option_value = IPTOS_THROUGHPUT;
131 EXPECT_TRUE(
132 posix_sock
133 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
134 reinterpret_cast<grpc_socket_mutator*>(&mutator))
135 .ok());
136
137 mutator.option_value = IPTOS_RELIABILITY;
138 EXPECT_TRUE(
139 posix_sock
140 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
141 reinterpret_cast<grpc_socket_mutator*>(&mutator))
142 .ok());
143
144 mutator.option_value = -1;
145 EXPECT_FALSE(
146 posix_sock
147 .SetSocketMutator(GRPC_FD_CLIENT_CONNECTION_USAGE,
148 reinterpret_cast<grpc_socket_mutator*>(&mutator))
149 .ok());
150 close(sock);
151 };
152 test_with_vtable(&mutator_vtable);
153 test_with_vtable(&mutator_vtable2);
154 }
155
TEST(TcpPosixSocketUtilsTest,SocketOptionsTest)156 TEST(TcpPosixSocketUtilsTest, SocketOptionsTest) {
157 int sock = socket(PF_INET, SOCK_STREAM, 0);
158 if (sock < 0) {
159 // Try ipv6
160 sock = socket(AF_INET6, SOCK_STREAM, 0);
161 }
162 EXPECT_GT(sock, 0);
163 PosixSocketWrapper posix_sock(sock);
164 EXPECT_TRUE(posix_sock.SetSocketNonBlocking(1).ok());
165 EXPECT_TRUE(posix_sock.SetSocketNonBlocking(0).ok());
166 EXPECT_TRUE(posix_sock.SetSocketCloexec(1).ok());
167 EXPECT_TRUE(posix_sock.SetSocketCloexec(0).ok());
168 EXPECT_TRUE(posix_sock.SetSocketReuseAddr(1).ok());
169 EXPECT_TRUE(posix_sock.SetSocketReuseAddr(0).ok());
170 EXPECT_TRUE(posix_sock.SetSocketLowLatency(1).ok());
171 EXPECT_TRUE(posix_sock.SetSocketLowLatency(0).ok());
172 close(sock);
173 }
174
175 } // namespace experimental
176 } // namespace grpc_event_engine
177
main(int argc,char ** argv)178 int main(int argc, char** argv) {
179 ::testing::InitGoogleTest(&argc, argv);
180 return RUN_ALL_TESTS();
181 }
182
183 #else // GRPC_POSIX_SOCKET_UTILS_COMMON
184
main(int argc,char ** argv)185 int main(int argc, char** argv) { return 0; }
186
187 #endif // GRPC_POSIX_SOCKET_UTILS_COMMON
188