xref: /aosp_15_r20/external/grpc-grpc/test/core/iomgr/socket_utils_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/lib/iomgr/port.h"
20 
21 // This test won't work except with posix sockets enabled
22 #ifdef GRPC_POSIX_SOCKET_UTILS_COMMON
23 
24 #include <errno.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27 #include <string.h>
28 
29 #include <gtest/gtest.h>
30 
31 #include <grpc/support/alloc.h>
32 #include <grpc/support/log.h>
33 #include <grpc/support/sync.h>
34 
35 #include "src/core/lib/gpr/useful.h"
36 #include "src/core/lib/gprpp/crash.h"
37 #include "src/core/lib/iomgr/socket_mutator.h"
38 #include "src/core/lib/iomgr/socket_utils_posix.h"
39 #include "test/core/util/test_config.h"
40 
41 struct test_socket_mutator {
42   grpc_socket_mutator base;
43   int option_value;
44 };
45 
mutate_fd(int fd,grpc_socket_mutator * mutator)46 static bool mutate_fd(int fd, grpc_socket_mutator* mutator) {
47   int newval;
48   socklen_t intlen = sizeof(newval);
49   struct test_socket_mutator* m =
50       reinterpret_cast<struct test_socket_mutator*>(mutator);
51 
52   if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &m->option_value,
53                       sizeof(m->option_value))) {
54     return false;
55   }
56   if (0 != getsockopt(fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
57     return false;
58   }
59   if (newval != m->option_value) {
60     return false;
61   }
62   return true;
63 }
64 
mutate_fd_2(const grpc_mutate_socket_info * info,grpc_socket_mutator * mutator)65 static bool mutate_fd_2(const grpc_mutate_socket_info* info,
66                         grpc_socket_mutator* mutator) {
67   int newval;
68   socklen_t intlen = sizeof(newval);
69   struct test_socket_mutator* m =
70       reinterpret_cast<struct test_socket_mutator*>(mutator);
71 
72   if (0 != setsockopt(info->fd, IPPROTO_IP, IP_TOS, &m->option_value,
73                       sizeof(m->option_value))) {
74     return false;
75   }
76   if (0 != getsockopt(info->fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
77     return false;
78   }
79   if (newval != m->option_value) {
80     return false;
81   }
82   return true;
83 }
84 
destroy_test_mutator(grpc_socket_mutator * mutator)85 static void destroy_test_mutator(grpc_socket_mutator* mutator) {
86   struct test_socket_mutator* m =
87       reinterpret_cast<struct test_socket_mutator*>(mutator);
88   gpr_free(m);
89 }
90 
compare_test_mutator(grpc_socket_mutator * a,grpc_socket_mutator * b)91 static int compare_test_mutator(grpc_socket_mutator* a,
92                                 grpc_socket_mutator* b) {
93   struct test_socket_mutator* ma =
94       reinterpret_cast<struct test_socket_mutator*>(a);
95   struct test_socket_mutator* mb =
96       reinterpret_cast<struct test_socket_mutator*>(b);
97   return grpc_core::QsortCompare(ma->option_value, mb->option_value);
98 }
99 
100 static const grpc_socket_mutator_vtable mutator_vtable = {
101     mutate_fd, compare_test_mutator, destroy_test_mutator, nullptr};
102 
103 static const grpc_socket_mutator_vtable mutator_vtable2 = {
104     nullptr, compare_test_mutator, destroy_test_mutator, mutate_fd_2};
105 
test_with_vtable(const grpc_socket_mutator_vtable * vtable)106 static void test_with_vtable(const grpc_socket_mutator_vtable* vtable) {
107   int sock = socket(PF_INET, SOCK_STREAM, 0);
108   ASSERT_GT(sock, 0);
109 
110   struct test_socket_mutator mutator;
111   grpc_socket_mutator_init(&mutator.base, vtable);
112 
113   mutator.option_value = IPTOS_LOWDELAY;
114   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
115       "set_socket_with_mutator",
116       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
117                                    (grpc_socket_mutator*)&mutator)));
118 
119   mutator.option_value = IPTOS_THROUGHPUT;
120   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
121       "set_socket_with_mutator",
122       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
123                                    (grpc_socket_mutator*)&mutator)));
124 
125   mutator.option_value = IPTOS_RELIABILITY;
126   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
127       "set_socket_with_mutator",
128       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
129                                    (grpc_socket_mutator*)&mutator)));
130 
131   mutator.option_value = -1;
132   auto err = grpc_set_socket_with_mutator(
133       sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
134       reinterpret_cast<grpc_socket_mutator*>(&mutator));
135   ASSERT_FALSE(err.ok());
136 }
137 
test_set_socket_dscp(int sock,int dscp)138 static void test_set_socket_dscp(int sock, int dscp) {
139   // Get the initial IP_TOS byte that consists of following bits:
140   // | 7 6 5 4 3 2 | 1 0 |
141   // |    DSCP     | ECN |
142   int optval;
143   socklen_t optlen = sizeof(optval);
144   ASSERT_TRUE(getsockopt(sock, IPPROTO_IP, IP_TOS, &optval, &optlen) == 0);
145   ASSERT_TRUE((optval >> 2) != dscp);
146 
147   ASSERT_TRUE(
148       GRPC_LOG_IF_ERROR("set_socket_dscp", grpc_set_socket_dscp(sock, dscp)));
149 
150   // Verify that value was changed
151   ASSERT_TRUE(getsockopt(sock, IPPROTO_IP, IP_TOS, &optval, &optlen) == 0);
152   ASSERT_TRUE((optval >> 2) == dscp);
153 }
154 
test_set_socket_dscp_ipv6(int sock,int dscp)155 static void test_set_socket_dscp_ipv6(int sock, int dscp) {
156   int optval;
157   socklen_t optlen = sizeof(optval);
158   // Get the initial IPPROTO_IPV6, same bit layout as IP_TOS above.
159   ASSERT_TRUE(getsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &optval, &optlen) ==
160               0);
161   ASSERT_TRUE((optval >> 2) != dscp);
162 
163   ASSERT_TRUE(
164       GRPC_LOG_IF_ERROR("set_socket_dscp", grpc_set_socket_dscp(sock, dscp)));
165 
166   // Verify that value was changed
167   ASSERT_TRUE(getsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &optval, &optlen) ==
168               0);
169   ASSERT_TRUE((optval >> 2) == dscp);
170 }
171 
TEST(SocketUtilsTest,MainTest)172 TEST(SocketUtilsTest, MainTest) {
173   int sock;
174 
175   sock = socket(PF_INET, SOCK_STREAM, 0);
176   ASSERT_GT(sock, 0);
177 
178   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_nonblocking",
179                                 grpc_set_socket_nonblocking(sock, 1)));
180   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_nonblocking",
181                                 grpc_set_socket_nonblocking(sock, 0)));
182   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_cloexec",
183                                 grpc_set_socket_cloexec(sock, 1)));
184   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_cloexec",
185                                 grpc_set_socket_cloexec(sock, 0)));
186   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_reuse_addr",
187                                 grpc_set_socket_reuse_addr(sock, 1)));
188   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_reuse_addr",
189                                 grpc_set_socket_reuse_addr(sock, 0)));
190   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_low_latency",
191                                 grpc_set_socket_low_latency(sock, 1)));
192   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_low_latency",
193                                 grpc_set_socket_low_latency(sock, 0)));
194   test_set_socket_dscp(sock, 8 /*CS1*/);
195   test_set_socket_dscp(sock, 16 /*CS2*/);
196 
197   close(sock);
198 
199   if (grpc_ipv6_loopback_available()) {
200     sock = socket(AF_INET6, SOCK_STREAM, 0);
201     GPR_ASSERT(sock > 0);
202 
203     test_set_socket_dscp_ipv6(sock, 8 /*CS1*/);
204     test_set_socket_dscp_ipv6(sock, 16 /*CS2*/);
205 
206     close(sock);
207   }
208 
209   test_with_vtable(&mutator_vtable);
210   test_with_vtable(&mutator_vtable2);
211 }
212 
main(int argc,char ** argv)213 int main(int argc, char** argv) {
214   grpc::testing::TestEnvironment env(&argc, argv);
215   ::testing::InitGoogleTest(&argc, argv);
216   return RUN_ALL_TESTS();
217 }
218 
219 #else  // GRPC_POSIX_SOCKET_UTILS_COMMON
220 
main(int argc,char ** argv)221 int main(int argc, char** argv) { return 1; }
222 
223 #endif  // GRPC_POSIX_SOCKET_UTILS_COMMON
224