• 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 <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