Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include <grpc/support/port_platform.h>
35 :
36 : #ifdef GPR_POSIX_SOCKET
37 :
38 : #include "src/core/iomgr/socket_utils_posix.h"
39 :
40 : #include <arpa/inet.h>
41 : #include <limits.h>
42 : #include <fcntl.h>
43 : #include <netinet/in.h>
44 : #include <netinet/tcp.h>
45 : #include <stdio.h>
46 : #include <sys/types.h>
47 : #include <sys/socket.h>
48 : #include <unistd.h>
49 : #include <string.h>
50 : #include <errno.h>
51 :
52 : #include "src/core/iomgr/sockaddr_utils.h"
53 : #include "src/core/support/string.h"
54 : #include <grpc/support/host_port.h>
55 : #include <grpc/support/log.h>
56 : #include <grpc/support/port_platform.h>
57 : #include <grpc/support/sync.h>
58 :
59 : /* set a socket to non blocking mode */
60 16461 : int grpc_set_socket_nonblocking(int fd, int non_blocking) {
61 16461 : int oldflags = fcntl(fd, F_GETFL, 0);
62 16461 : if (oldflags < 0) {
63 0 : return 0;
64 : }
65 :
66 16461 : if (non_blocking) {
67 16461 : oldflags |= O_NONBLOCK;
68 : } else {
69 0 : oldflags &= ~O_NONBLOCK;
70 : }
71 :
72 16461 : if (fcntl(fd, F_SETFL, oldflags) != 0) {
73 0 : return 0;
74 : }
75 :
76 16461 : return 1;
77 : }
78 :
79 20517 : int grpc_set_socket_no_sigpipe_if_possible(int fd) {
80 : #ifdef GPR_HAVE_SO_NOSIGPIPE
81 : int val = 1;
82 : int newval;
83 : socklen_t intlen = sizeof(newval);
84 : return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) &&
85 : 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) &&
86 : (newval != 0) == val;
87 : #else
88 20517 : return 1;
89 : #endif
90 : }
91 :
92 : /* set a socket to close on exec */
93 16361 : int grpc_set_socket_cloexec(int fd, int close_on_exec) {
94 16361 : int oldflags = fcntl(fd, F_GETFD, 0);
95 16361 : if (oldflags < 0) {
96 0 : return 0;
97 : }
98 :
99 16361 : if (close_on_exec) {
100 16361 : oldflags |= FD_CLOEXEC;
101 : } else {
102 0 : oldflags &= ~FD_CLOEXEC;
103 : }
104 :
105 16361 : if (fcntl(fd, F_SETFD, oldflags) != 0) {
106 0 : return 0;
107 : }
108 :
109 16361 : return 1;
110 : }
111 :
112 : /* set a socket to reuse old addresses */
113 4064 : int grpc_set_socket_reuse_addr(int fd, int reuse) {
114 4064 : int val = (reuse != 0);
115 : int newval;
116 4064 : socklen_t intlen = sizeof(newval);
117 12192 : return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
118 8128 : 0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
119 4064 : (newval != 0) == val;
120 : }
121 :
122 : /* disable nagle */
123 15369 : int grpc_set_socket_low_latency(int fd, int low_latency) {
124 15369 : int val = (low_latency != 0);
125 : int newval;
126 15369 : socklen_t intlen = sizeof(newval);
127 46107 : return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
128 30738 : 0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
129 15369 : (newval != 0) == val;
130 : }
131 :
132 : static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
133 : static int g_ipv6_loopback_available;
134 :
135 519 : static void probe_ipv6_once(void) {
136 519 : int fd = socket(AF_INET6, SOCK_STREAM, 0);
137 519 : g_ipv6_loopback_available = 0;
138 519 : if (fd < 0) {
139 0 : gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
140 : } else {
141 : struct sockaddr_in6 addr;
142 519 : memset(&addr, 0, sizeof(addr));
143 519 : addr.sin6_family = AF_INET6;
144 519 : addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
145 519 : if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
146 519 : g_ipv6_loopback_available = 1;
147 : } else {
148 0 : gpr_log(GPR_INFO,
149 : "Disabling AF_INET6 sockets because ::1 is not available.");
150 : }
151 519 : close(fd);
152 : }
153 519 : }
154 :
155 15360 : int grpc_ipv6_loopback_available(void) {
156 15360 : gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
157 15360 : return g_ipv6_loopback_available;
158 : }
159 :
160 : /* This should be 0 in production, but it may be enabled for testing or
161 : debugging purposes, to simulate an environment where IPv6 sockets can't
162 : also speak IPv4. */
163 : int grpc_forbid_dualstack_sockets_for_testing = 0;
164 :
165 15358 : static int set_socket_dualstack(int fd) {
166 15358 : if (!grpc_forbid_dualstack_sockets_for_testing) {
167 15117 : const int off = 0;
168 15117 : return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
169 : } else {
170 : /* Force an IPv6-only socket, for testing purposes. */
171 241 : const int on = 1;
172 241 : setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
173 241 : return 0;
174 : }
175 : }
176 :
177 16361 : int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
178 : int protocol, grpc_dualstack_mode *dsmode) {
179 16361 : int family = addr->sa_family;
180 16361 : if (family == AF_INET6) {
181 : int fd;
182 15358 : if (grpc_ipv6_loopback_available()) {
183 15358 : fd = socket(family, type, protocol);
184 : } else {
185 0 : fd = -1;
186 0 : errno = EAFNOSUPPORT;
187 : }
188 : /* Check if we've got a valid dualstack socket. */
189 15358 : if (fd >= 0 && set_socket_dualstack(fd)) {
190 15117 : *dsmode = GRPC_DSMODE_DUALSTACK;
191 15117 : return fd;
192 : }
193 : /* If this isn't an IPv4 address, then return whatever we've got. */
194 241 : if (!grpc_sockaddr_is_v4mapped(addr, NULL)) {
195 127 : *dsmode = GRPC_DSMODE_IPV6;
196 127 : return fd;
197 : }
198 : /* Fall back to AF_INET. */
199 114 : if (fd >= 0) {
200 114 : close(fd);
201 : }
202 114 : family = AF_INET;
203 : }
204 1117 : *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
205 1117 : return socket(family, type, protocol);
206 : }
207 :
208 : #endif
|