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