• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <grpc/support/alloc.h>
26 #include <grpc/support/sync.h>
27 #include <gtest/gtest.h>
28 #include <netinet/in.h>
29 #include <netinet/ip.h>
30 #include <string.h>
31 
32 #include "absl/log/check.h"
33 #include "src/core/lib/iomgr/socket_mutator.h"
34 #include "src/core/lib/iomgr/socket_utils_posix.h"
35 #include "src/core/util/crash.h"
36 #include "src/core/util/useful.h"
37 #include "test/core/test_util/test_config.h"
38 
39 struct test_socket_mutator {
40   grpc_socket_mutator base;
41   int option_value;
42 };
43 
mutate_fd(int fd,grpc_socket_mutator * mutator)44 static bool mutate_fd(int fd, grpc_socket_mutator* mutator) {
45   int newval;
46   socklen_t intlen = sizeof(newval);
47   struct test_socket_mutator* m =
48       reinterpret_cast<struct test_socket_mutator*>(mutator);
49 
50   if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &m->option_value,
51                       sizeof(m->option_value))) {
52     return false;
53   }
54   if (0 != getsockopt(fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
55     return false;
56   }
57   if (newval != m->option_value) {
58     return false;
59   }
60   return true;
61 }
62 
mutate_fd_2(const grpc_mutate_socket_info * info,grpc_socket_mutator * mutator)63 static bool mutate_fd_2(const grpc_mutate_socket_info* info,
64                         grpc_socket_mutator* mutator) {
65   int newval;
66   socklen_t intlen = sizeof(newval);
67   struct test_socket_mutator* m =
68       reinterpret_cast<struct test_socket_mutator*>(mutator);
69 
70   if (0 != setsockopt(info->fd, IPPROTO_IP, IP_TOS, &m->option_value,
71                       sizeof(m->option_value))) {
72     return false;
73   }
74   if (0 != getsockopt(info->fd, IPPROTO_IP, IP_TOS, &newval, &intlen)) {
75     return false;
76   }
77   if (newval != m->option_value) {
78     return false;
79   }
80   return true;
81 }
82 
destroy_test_mutator(grpc_socket_mutator * mutator)83 static void destroy_test_mutator(grpc_socket_mutator* mutator) {
84   struct test_socket_mutator* m =
85       reinterpret_cast<struct test_socket_mutator*>(mutator);
86   gpr_free(m);
87 }
88 
compare_test_mutator(grpc_socket_mutator * a,grpc_socket_mutator * b)89 static int compare_test_mutator(grpc_socket_mutator* a,
90                                 grpc_socket_mutator* b) {
91   struct test_socket_mutator* ma =
92       reinterpret_cast<struct test_socket_mutator*>(a);
93   struct test_socket_mutator* mb =
94       reinterpret_cast<struct test_socket_mutator*>(b);
95   return grpc_core::QsortCompare(ma->option_value, mb->option_value);
96 }
97 
98 static const grpc_socket_mutator_vtable mutator_vtable = {
99     mutate_fd, compare_test_mutator, destroy_test_mutator, nullptr};
100 
101 static const grpc_socket_mutator_vtable mutator_vtable2 = {
102     nullptr, compare_test_mutator, destroy_test_mutator, mutate_fd_2};
103 
test_with_vtable(const grpc_socket_mutator_vtable * vtable)104 static void test_with_vtable(const grpc_socket_mutator_vtable* vtable) {
105   int sock = socket(PF_INET, SOCK_STREAM, 0);
106   ASSERT_GT(sock, 0);
107 
108   struct test_socket_mutator mutator;
109   grpc_socket_mutator_init(&mutator.base, vtable);
110 
111   mutator.option_value = IPTOS_LOWDELAY;
112   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
113       "set_socket_with_mutator",
114       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
115                                    (grpc_socket_mutator*)&mutator)));
116 
117   mutator.option_value = IPTOS_THROUGHPUT;
118   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
119       "set_socket_with_mutator",
120       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
121                                    (grpc_socket_mutator*)&mutator)));
122 
123   mutator.option_value = IPTOS_RELIABILITY;
124   ASSERT_TRUE(GRPC_LOG_IF_ERROR(
125       "set_socket_with_mutator",
126       grpc_set_socket_with_mutator(sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
127                                    (grpc_socket_mutator*)&mutator)));
128 
129   mutator.option_value = -1;
130   auto err = grpc_set_socket_with_mutator(
131       sock, GRPC_FD_CLIENT_CONNECTION_USAGE,
132       reinterpret_cast<grpc_socket_mutator*>(&mutator));
133   ASSERT_FALSE(err.ok());
134 }
135 
test_set_socket_dscp(int sock,int dscp)136 static void test_set_socket_dscp(int sock, int dscp) {
137   // Get the initial IP_TOS byte that consists of following bits:
138   // | 7 6 5 4 3 2 | 1 0 |
139   // |    DSCP     | ECN |
140   int optval;
141   socklen_t optlen = sizeof(optval);
142   ASSERT_TRUE(getsockopt(sock, IPPROTO_IP, IP_TOS, &optval, &optlen) == 0);
143   ASSERT_TRUE((optval >> 2) != dscp);
144 
145   ASSERT_TRUE(
146       GRPC_LOG_IF_ERROR("set_socket_dscp", grpc_set_socket_dscp(sock, dscp)));
147 
148   // Verify that value was changed
149   ASSERT_TRUE(getsockopt(sock, IPPROTO_IP, IP_TOS, &optval, &optlen) == 0);
150   ASSERT_TRUE((optval >> 2) == dscp);
151 }
152 
test_set_socket_dscp_ipv6(int sock,int dscp)153 static void test_set_socket_dscp_ipv6(int sock, int dscp) {
154   int optval;
155   socklen_t optlen = sizeof(optval);
156   // Get the initial IPPROTO_IPV6, same bit layout as IP_TOS above.
157   ASSERT_TRUE(getsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &optval, &optlen) ==
158               0);
159   ASSERT_TRUE((optval >> 2) != dscp);
160 
161   ASSERT_TRUE(
162       GRPC_LOG_IF_ERROR("set_socket_dscp", grpc_set_socket_dscp(sock, dscp)));
163 
164   // Verify that value was changed
165   ASSERT_TRUE(getsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &optval, &optlen) ==
166               0);
167   ASSERT_TRUE((optval >> 2) == dscp);
168 }
169 
TEST(SocketUtilsTest,MainTest)170 TEST(SocketUtilsTest, MainTest) {
171   int sock;
172 
173   sock = socket(PF_INET, SOCK_STREAM, 0);
174   ASSERT_GT(sock, 0);
175 
176   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_nonblocking",
177                                 grpc_set_socket_nonblocking(sock, 1)));
178   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_nonblocking",
179                                 grpc_set_socket_nonblocking(sock, 0)));
180   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_cloexec",
181                                 grpc_set_socket_cloexec(sock, 1)));
182   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_cloexec",
183                                 grpc_set_socket_cloexec(sock, 0)));
184   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_reuse_addr",
185                                 grpc_set_socket_reuse_addr(sock, 1)));
186   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_reuse_addr",
187                                 grpc_set_socket_reuse_addr(sock, 0)));
188   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_low_latency",
189                                 grpc_set_socket_low_latency(sock, 1)));
190   ASSERT_TRUE(GRPC_LOG_IF_ERROR("set_socket_low_latency",
191                                 grpc_set_socket_low_latency(sock, 0)));
192   test_set_socket_dscp(sock, 8 /*CS1*/);
193   test_set_socket_dscp(sock, 16 /*CS2*/);
194 
195   close(sock);
196 
197   if (grpc_ipv6_loopback_available()) {
198     sock = socket(AF_INET6, SOCK_STREAM, 0);
199     CHECK_GT(sock, 0);
200 
201     test_set_socket_dscp_ipv6(sock, 8 /*CS1*/);
202     test_set_socket_dscp_ipv6(sock, 16 /*CS2*/);
203 
204     close(sock);
205   }
206 
207   test_with_vtable(&mutator_vtable);
208   test_with_vtable(&mutator_vtable2);
209 }
210 
main(int argc,char ** argv)211 int main(int argc, char** argv) {
212   grpc::testing::TestEnvironment env(&argc, argv);
213   ::testing::InitGoogleTest(&argc, argv);
214   return RUN_ALL_TESTS();
215 }
216 
217 #else  // GRPC_POSIX_SOCKET_UTILS_COMMON
218 
main(int argc,char ** argv)219 int main(int argc, char** argv) { return 1; }
220 
221 #endif  // GRPC_POSIX_SOCKET_UTILS_COMMON
222