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 <grpc/support/port_platform.h>
20
21 #include "src/core/lib/iomgr/port.h"
22
23 #ifdef GRPC_POSIX_SOCKET_UTILS_COMMON
24
25 #include "src/core/lib/iomgr/socket_utils.h"
26 #include "src/core/lib/iomgr/socket_utils_posix.h"
27
28 #include <arpa/inet.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <netinet/in.h>
33 #include <netinet/tcp.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39
40 #include <grpc/support/alloc.h>
41 #include <grpc/support/log.h>
42 #include <grpc/support/sync.h>
43
44 #include "src/core/lib/channel/channel_args.h"
45 #include "src/core/lib/gpr/host_port.h"
46 #include "src/core/lib/gpr/string.h"
47 #include "src/core/lib/iomgr/sockaddr.h"
48 #include "src/core/lib/iomgr/sockaddr_utils.h"
49
50 /* set a socket to non blocking mode */
grpc_set_socket_nonblocking(int fd,int non_blocking)51 grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking) {
52 int oldflags = fcntl(fd, F_GETFL, 0);
53 if (oldflags < 0) {
54 return GRPC_OS_ERROR(errno, "fcntl");
55 }
56
57 if (non_blocking) {
58 oldflags |= O_NONBLOCK;
59 } else {
60 oldflags &= ~O_NONBLOCK;
61 }
62
63 if (fcntl(fd, F_SETFL, oldflags) != 0) {
64 return GRPC_OS_ERROR(errno, "fcntl");
65 }
66
67 return GRPC_ERROR_NONE;
68 }
69
grpc_set_socket_no_sigpipe_if_possible(int fd)70 grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd) {
71 #ifdef GRPC_HAVE_SO_NOSIGPIPE
72 int val = 1;
73 int newval;
74 socklen_t intlen = sizeof(newval);
75 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
76 return GRPC_OS_ERROR(errno, "setsockopt(SO_NOSIGPIPE)");
77 }
78 if (0 != getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen)) {
79 return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)");
80 }
81 if ((newval != 0) != (val != 0)) {
82 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_NOSIGPIPE");
83 }
84 #endif
85 return GRPC_ERROR_NONE;
86 }
87
grpc_set_socket_ip_pktinfo_if_possible(int fd)88 grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd) {
89 #ifdef GRPC_HAVE_IP_PKTINFO
90 int get_local_ip = 1;
91 if (0 != setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
92 sizeof(get_local_ip))) {
93 return GRPC_OS_ERROR(errno, "setsockopt(IP_PKTINFO)");
94 }
95 #endif
96 return GRPC_ERROR_NONE;
97 }
98
grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd)99 grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
100 #ifdef GRPC_HAVE_IPV6_RECVPKTINFO
101 int get_local_ip = 1;
102 if (0 != setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
103 sizeof(get_local_ip))) {
104 return GRPC_OS_ERROR(errno, "setsockopt(IPV6_RECVPKTINFO)");
105 }
106 #endif
107 return GRPC_ERROR_NONE;
108 }
109
grpc_set_socket_sndbuf(int fd,int buffer_size_bytes)110 grpc_error* grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
111 return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
112 sizeof(buffer_size_bytes))
113 ? GRPC_ERROR_NONE
114 : GRPC_OS_ERROR(errno, "setsockopt(SO_SNDBUF)");
115 }
116
grpc_set_socket_rcvbuf(int fd,int buffer_size_bytes)117 grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
118 return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
119 sizeof(buffer_size_bytes))
120 ? GRPC_ERROR_NONE
121 : GRPC_OS_ERROR(errno, "setsockopt(SO_RCVBUF)");
122 }
123
124 /* set a socket to close on exec */
grpc_set_socket_cloexec(int fd,int close_on_exec)125 grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec) {
126 int oldflags = fcntl(fd, F_GETFD, 0);
127 if (oldflags < 0) {
128 return GRPC_OS_ERROR(errno, "fcntl");
129 }
130
131 if (close_on_exec) {
132 oldflags |= FD_CLOEXEC;
133 } else {
134 oldflags &= ~FD_CLOEXEC;
135 }
136
137 if (fcntl(fd, F_SETFD, oldflags) != 0) {
138 return GRPC_OS_ERROR(errno, "fcntl");
139 }
140
141 return GRPC_ERROR_NONE;
142 }
143
144 /* set a socket to reuse old addresses */
grpc_set_socket_reuse_addr(int fd,int reuse)145 grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse) {
146 int val = (reuse != 0);
147 int newval;
148 socklen_t intlen = sizeof(newval);
149 if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
150 return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEADDR)");
151 }
152 if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen)) {
153 return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)");
154 }
155 if ((newval != 0) != val) {
156 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEADDR");
157 }
158
159 return GRPC_ERROR_NONE;
160 }
161
162 /* set a socket to reuse old addresses */
grpc_set_socket_reuse_port(int fd,int reuse)163 grpc_error* grpc_set_socket_reuse_port(int fd, int reuse) {
164 #ifndef SO_REUSEPORT
165 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
166 "SO_REUSEPORT unavailable on compiling system");
167 #else
168 int val = (reuse != 0);
169 int newval;
170 socklen_t intlen = sizeof(newval);
171 if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))) {
172 return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEPORT)");
173 }
174 if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &newval, &intlen)) {
175 return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)");
176 }
177 if ((newval != 0) != val) {
178 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEPORT");
179 }
180
181 return GRPC_ERROR_NONE;
182 #endif
183 }
184
185 static gpr_once g_probe_so_reuesport_once = GPR_ONCE_INIT;
186 static int g_support_so_reuseport = false;
187
probe_so_reuseport_once(void)188 void probe_so_reuseport_once(void) {
189 #ifndef GPR_MANYLINUX1
190 int s = socket(AF_INET, SOCK_STREAM, 0);
191 if (s < 0) {
192 /* This might be an ipv6-only environment in which case 'socket(AF_INET,..)'
193 call would fail. Try creating IPv6 socket in that case */
194 s = socket(AF_INET6, SOCK_STREAM, 0);
195 }
196 if (s >= 0) {
197 g_support_so_reuseport = GRPC_LOG_IF_ERROR(
198 "check for SO_REUSEPORT", grpc_set_socket_reuse_port(s, 1));
199 close(s);
200 }
201 #endif
202 }
203
grpc_is_socket_reuse_port_supported()204 bool grpc_is_socket_reuse_port_supported() {
205 gpr_once_init(&g_probe_so_reuesport_once, probe_so_reuseport_once);
206 return g_support_so_reuseport;
207 }
208
209 /* disable nagle */
grpc_set_socket_low_latency(int fd,int low_latency)210 grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
211 int val = (low_latency != 0);
212 int newval;
213 socklen_t intlen = sizeof(newval);
214 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) {
215 return GRPC_OS_ERROR(errno, "setsockopt(TCP_NODELAY)");
216 }
217 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen)) {
218 return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)");
219 }
220 if ((newval != 0) != val) {
221 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set TCP_NODELAY");
222 }
223 return GRPC_ERROR_NONE;
224 }
225
226 /* The default values for TCP_USER_TIMEOUT are currently configured to be in
227 * line with the default values of KEEPALIVE_TIMEOUT as proposed in
228 * https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */
229 #define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
230 #define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
231
232 static int g_default_client_tcp_user_timeout_ms =
233 DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
234 static int g_default_server_tcp_user_timeout_ms =
235 DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
236 static bool g_default_client_tcp_user_timeout_enabled = false;
237 static bool g_default_server_tcp_user_timeout_enabled = true;
238
config_default_tcp_user_timeout(bool enable,int timeout,bool is_client)239 void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
240 if (is_client) {
241 g_default_client_tcp_user_timeout_enabled = enable;
242 if (timeout > 0) {
243 g_default_client_tcp_user_timeout_ms = timeout;
244 }
245 } else {
246 g_default_server_tcp_user_timeout_enabled = enable;
247 if (timeout > 0) {
248 g_default_server_tcp_user_timeout_ms = timeout;
249 }
250 }
251 }
252
253 /* Set TCP_USER_TIMEOUT */
grpc_set_socket_tcp_user_timeout(int fd,const grpc_channel_args * channel_args,bool is_client)254 grpc_error* grpc_set_socket_tcp_user_timeout(
255 int fd, const grpc_channel_args* channel_args, bool is_client) {
256 #ifdef GRPC_HAVE_TCP_USER_TIMEOUT
257 bool enable;
258 int timeout;
259 if (is_client) {
260 enable = g_default_client_tcp_user_timeout_enabled;
261 timeout = g_default_client_tcp_user_timeout_ms;
262 } else {
263 enable = g_default_server_tcp_user_timeout_enabled;
264 timeout = g_default_server_tcp_user_timeout_ms;
265 }
266 if (channel_args) {
267 for (unsigned int i = 0; i < channel_args->num_args; i++) {
268 if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
269 const int value = grpc_channel_arg_get_integer(
270 &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
271 /* Continue using default if value is 0 */
272 if (value == 0) {
273 continue;
274 }
275 /* Disable if value is INT_MAX */
276 enable = value != INT_MAX;
277 } else if (0 == strcmp(channel_args->args[i].key,
278 GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
279 const int value = grpc_channel_arg_get_integer(
280 &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
281 /* Continue using default if value is 0 */
282 if (value == 0) {
283 continue;
284 }
285 timeout = value;
286 }
287 }
288 }
289 if (enable) {
290 extern grpc_core::TraceFlag grpc_tcp_trace;
291 if (grpc_tcp_trace.enabled()) {
292 gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
293 timeout);
294 }
295 int newval;
296 socklen_t len = sizeof(newval);
297 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
298 sizeof(timeout))) {
299 return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)");
300 }
301 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
302 return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)");
303 }
304 if (newval != timeout) {
305 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
306 "Failed to set TCP_USER_TIMEOUT");
307 }
308 }
309 #else
310 gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
311 #endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
312 return GRPC_ERROR_NONE;
313 }
314
315 /* set a socket using a grpc_socket_mutator */
grpc_set_socket_with_mutator(int fd,grpc_socket_mutator * mutator)316 grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
317 GPR_ASSERT(mutator);
318 if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
319 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed.");
320 }
321 return GRPC_ERROR_NONE;
322 }
323
324 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
325 static int g_ipv6_loopback_available;
326
probe_ipv6_once(void)327 static void probe_ipv6_once(void) {
328 int fd = socket(AF_INET6, SOCK_STREAM, 0);
329 g_ipv6_loopback_available = 0;
330 if (fd < 0) {
331 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
332 } else {
333 grpc_sockaddr_in6 addr;
334 memset(&addr, 0, sizeof(addr));
335 addr.sin6_family = AF_INET6;
336 addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
337 if (bind(fd, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
338 g_ipv6_loopback_available = 1;
339 } else {
340 gpr_log(GPR_INFO,
341 "Disabling AF_INET6 sockets because ::1 is not available.");
342 }
343 close(fd);
344 }
345 }
346
grpc_ipv6_loopback_available(void)347 int grpc_ipv6_loopback_available(void) {
348 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
349 return g_ipv6_loopback_available;
350 }
351
352 /* This should be 0 in production, but it may be enabled for testing or
353 debugging purposes, to simulate an environment where IPv6 sockets can't
354 also speak IPv4. */
355 int grpc_forbid_dualstack_sockets_for_testing = 0;
356
set_socket_dualstack(int fd)357 static int set_socket_dualstack(int fd) {
358 if (!grpc_forbid_dualstack_sockets_for_testing) {
359 const int off = 0;
360 return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
361 } else {
362 /* Force an IPv6-only socket, for testing purposes. */
363 const int on = 1;
364 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
365 return 0;
366 }
367 }
368
error_for_fd(int fd,const grpc_resolved_address * addr)369 static grpc_error* error_for_fd(int fd, const grpc_resolved_address* addr) {
370 if (fd >= 0) return GRPC_ERROR_NONE;
371 char* addr_str;
372 grpc_sockaddr_to_string(&addr_str, addr, 0);
373 grpc_error* err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"),
374 GRPC_ERROR_STR_TARGET_ADDRESS,
375 grpc_slice_from_copied_string(addr_str));
376 gpr_free(addr_str);
377 return err;
378 }
379
grpc_create_dualstack_socket(const grpc_resolved_address * resolved_addr,int type,int protocol,grpc_dualstack_mode * dsmode,int * newfd)380 grpc_error* grpc_create_dualstack_socket(
381 const grpc_resolved_address* resolved_addr, int type, int protocol,
382 grpc_dualstack_mode* dsmode, int* newfd) {
383 return grpc_create_dualstack_socket_using_factory(
384 nullptr, resolved_addr, type, protocol, dsmode, newfd);
385 }
386
create_socket(grpc_socket_factory * factory,int domain,int type,int protocol)387 static int create_socket(grpc_socket_factory* factory, int domain, int type,
388 int protocol) {
389 return (factory != nullptr)
390 ? grpc_socket_factory_socket(factory, domain, type, protocol)
391 : socket(domain, type, protocol);
392 }
393
grpc_create_dualstack_socket_using_factory(grpc_socket_factory * factory,const grpc_resolved_address * resolved_addr,int type,int protocol,grpc_dualstack_mode * dsmode,int * newfd)394 grpc_error* grpc_create_dualstack_socket_using_factory(
395 grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
396 int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
397 const grpc_sockaddr* addr =
398 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
399 int family = addr->sa_family;
400 if (family == AF_INET6) {
401 if (grpc_ipv6_loopback_available()) {
402 *newfd = create_socket(factory, family, type, protocol);
403 } else {
404 *newfd = -1;
405 errno = EAFNOSUPPORT;
406 }
407 /* Check if we've got a valid dualstack socket. */
408 if (*newfd >= 0 && set_socket_dualstack(*newfd)) {
409 *dsmode = GRPC_DSMODE_DUALSTACK;
410 return GRPC_ERROR_NONE;
411 }
412 /* If this isn't an IPv4 address, then return whatever we've got. */
413 if (!grpc_sockaddr_is_v4mapped(resolved_addr, nullptr)) {
414 *dsmode = GRPC_DSMODE_IPV6;
415 return error_for_fd(*newfd, resolved_addr);
416 }
417 /* Fall back to AF_INET. */
418 if (*newfd >= 0) {
419 close(*newfd);
420 }
421 family = AF_INET;
422 }
423 *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
424 *newfd = create_socket(factory, family, type, protocol);
425 return error_for_fd(*newfd, resolved_addr);
426 }
427
grpc_htons(uint16_t hostshort)428 uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
429
grpc_ntohs(uint16_t netshort)430 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
431
grpc_htonl(uint32_t hostlong)432 uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
433
grpc_ntohl(uint32_t netlong)434 uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
435
grpc_inet_pton(int af,const char * src,void * dst)436 int grpc_inet_pton(int af, const char* src, void* dst) {
437 return inet_pton(af, src, dst);
438 }
439
grpc_inet_ntop(int af,const void * src,char * dst,size_t size)440 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
441 GPR_ASSERT(size <= (socklen_t)-1);
442 return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
443 }
444
445 #endif
446