Home | History | Annotate | Download | only in iomgr
      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 */
     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 
     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 
     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 
     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 
    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 
    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 */
    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 */
    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 */
    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 
    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 
    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 */
    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 
    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 */
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    428 uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
    429 
    430 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
    431 
    432 uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
    433 
    434 uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
    435 
    436 int grpc_inet_pton(int af, const char* src, void* dst) {
    437   return inet_pton(af, src, dst);
    438 }
    439 
    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