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