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