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 <arpa/inet.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <limits.h>
29 #include <netinet/in.h>
30
31 #include "src/core/lib/iomgr/socket_utils.h"
32 #include "src/core/lib/iomgr/socket_utils_posix.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/event_engine/endpoint_config.h>
47 #include <grpc/support/alloc.h>
48 #include <grpc/support/log.h>
49 #include <grpc/support/sync.h>
50
51 #include "src/core/lib/address_utils/sockaddr_utils.h"
52 #include "src/core/lib/gpr/string.h"
53 #include "src/core/lib/gprpp/crash.h"
54 #include "src/core/lib/gprpp/strerror.h"
55 #include "src/core/lib/iomgr/sockaddr.h"
56
57 // set a socket to use zerocopy
grpc_set_socket_zerocopy(int fd)58 grpc_error_handle grpc_set_socket_zerocopy(int fd) {
59 #ifdef GRPC_LINUX_ERRQUEUE
60 const int enable = 1;
61 auto err = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &enable, sizeof(enable));
62 if (err != 0) {
63 return GRPC_OS_ERROR(errno, "setsockopt(SO_ZEROCOPY)");
64 }
65 return absl::OkStatus();
66 #else
67 (void)fd;
68 return GRPC_OS_ERROR(ENOSYS, "setsockopt(SO_ZEROCOPY)");
69 #endif
70 }
71
72 // set a socket to non blocking mode
grpc_set_socket_nonblocking(int fd,int non_blocking)73 grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking) {
74 int oldflags = fcntl(fd, F_GETFL, 0);
75 if (oldflags < 0) {
76 return GRPC_OS_ERROR(errno, "fcntl");
77 }
78
79 if (non_blocking) {
80 oldflags |= O_NONBLOCK;
81 } else {
82 oldflags &= ~O_NONBLOCK;
83 }
84
85 if (fcntl(fd, F_SETFL, oldflags) != 0) {
86 return GRPC_OS_ERROR(errno, "fcntl");
87 }
88
89 return absl::OkStatus();
90 }
91
grpc_set_socket_no_sigpipe_if_possible(int fd)92 grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd) {
93 #ifdef GRPC_HAVE_SO_NOSIGPIPE
94 int val = 1;
95 int newval;
96 socklen_t intlen = sizeof(newval);
97 if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
98 return GRPC_OS_ERROR(errno, "setsockopt(SO_NOSIGPIPE)");
99 }
100 if (0 != getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen)) {
101 return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)");
102 }
103 if ((newval != 0) != (val != 0)) {
104 return GRPC_ERROR_CREATE("Failed to set SO_NOSIGPIPE");
105 }
106 #else
107 // Avoid unused parameter warning for conditional parameter
108 (void)fd;
109 #endif
110 return absl::OkStatus();
111 }
112
grpc_set_socket_ip_pktinfo_if_possible(int fd)113 grpc_error_handle grpc_set_socket_ip_pktinfo_if_possible(int fd) {
114 // Use conditionally-important parameter to avoid warning
115 (void)fd;
116 #ifdef GRPC_HAVE_IP_PKTINFO
117 int get_local_ip = 1;
118 if (0 != setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
119 sizeof(get_local_ip))) {
120 return GRPC_OS_ERROR(errno, "setsockopt(IP_PKTINFO)");
121 }
122 #endif
123 return absl::OkStatus();
124 }
125
grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd)126 grpc_error_handle grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
127 // Use conditionally-important parameter to avoid warning
128 (void)fd;
129 #ifdef GRPC_HAVE_IPV6_RECVPKTINFO
130 int get_local_ip = 1;
131 if (0 != setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
132 sizeof(get_local_ip))) {
133 return GRPC_OS_ERROR(errno, "setsockopt(IPV6_RECVPKTINFO)");
134 }
135 #endif
136 return absl::OkStatus();
137 }
138
grpc_set_socket_sndbuf(int fd,int buffer_size_bytes)139 grpc_error_handle grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
140 return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
141 sizeof(buffer_size_bytes))
142 ? absl::OkStatus()
143 : GRPC_OS_ERROR(errno, "setsockopt(SO_SNDBUF)");
144 }
145
grpc_set_socket_rcvbuf(int fd,int buffer_size_bytes)146 grpc_error_handle grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
147 return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
148 sizeof(buffer_size_bytes))
149 ? absl::OkStatus()
150 : GRPC_OS_ERROR(errno, "setsockopt(SO_RCVBUF)");
151 }
152
153 // set a socket to close on exec
grpc_set_socket_cloexec(int fd,int close_on_exec)154 grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec) {
155 int oldflags = fcntl(fd, F_GETFD, 0);
156 if (oldflags < 0) {
157 return GRPC_OS_ERROR(errno, "fcntl");
158 }
159
160 if (close_on_exec) {
161 oldflags |= FD_CLOEXEC;
162 } else {
163 oldflags &= ~FD_CLOEXEC;
164 }
165
166 if (fcntl(fd, F_SETFD, oldflags) != 0) {
167 return GRPC_OS_ERROR(errno, "fcntl");
168 }
169
170 return absl::OkStatus();
171 }
172
173 // set a socket to reuse old addresses
grpc_set_socket_reuse_addr(int fd,int reuse)174 grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse) {
175 int val = (reuse != 0);
176 int newval;
177 socklen_t intlen = sizeof(newval);
178 if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
179 return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEADDR)");
180 }
181 if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen)) {
182 return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)");
183 }
184 if ((newval != 0) != val) {
185 return GRPC_ERROR_CREATE("Failed to set SO_REUSEADDR");
186 }
187
188 return absl::OkStatus();
189 }
190
191 // set a socket to reuse old addresses
grpc_set_socket_reuse_port(int fd,int reuse)192 grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse) {
193 #ifndef SO_REUSEPORT
194 return GRPC_ERROR_CREATE("SO_REUSEPORT unavailable on compiling system");
195 #else
196 int val = (reuse != 0);
197 int newval;
198 socklen_t intlen = sizeof(newval);
199 if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))) {
200 return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEPORT)");
201 }
202 if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &newval, &intlen)) {
203 return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)");
204 }
205 if ((newval != 0) != val) {
206 return GRPC_ERROR_CREATE("Failed to set SO_REUSEPORT");
207 }
208
209 return absl::OkStatus();
210 #endif
211 }
212
213 static gpr_once g_probe_so_reuesport_once = GPR_ONCE_INIT;
214 static int g_support_so_reuseport = false;
215
probe_so_reuseport_once(void)216 void probe_so_reuseport_once(void) {
217 int s = socket(AF_INET, SOCK_STREAM, 0);
218 if (s < 0) {
219 // This might be an ipv6-only environment in which case 'socket(AF_INET,..)'
220 // call would fail. Try creating IPv6 socket in that case
221 s = socket(AF_INET6, SOCK_STREAM, 0);
222 }
223 if (s >= 0) {
224 g_support_so_reuseport = GRPC_LOG_IF_ERROR(
225 "check for SO_REUSEPORT", grpc_set_socket_reuse_port(s, 1));
226 close(s);
227 }
228 }
229
grpc_is_socket_reuse_port_supported()230 bool grpc_is_socket_reuse_port_supported() {
231 gpr_once_init(&g_probe_so_reuesport_once, probe_so_reuseport_once);
232 return g_support_so_reuseport;
233 }
234
235 // disable nagle
grpc_set_socket_low_latency(int fd,int low_latency)236 grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency) {
237 int val = (low_latency != 0);
238 int newval;
239 socklen_t intlen = sizeof(newval);
240 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) {
241 return GRPC_OS_ERROR(errno, "setsockopt(TCP_NODELAY)");
242 }
243 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen)) {
244 return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)");
245 }
246 if ((newval != 0) != val) {
247 return GRPC_ERROR_CREATE("Failed to set TCP_NODELAY");
248 }
249 return absl::OkStatus();
250 }
251
252 /* Set Differentiated Services Code Point (DSCP) */
grpc_set_socket_dscp(int fd,int dscp)253 grpc_error_handle grpc_set_socket_dscp(int fd, int dscp) {
254 if (dscp == grpc_core::PosixTcpOptions::kDscpNotSet) {
255 return absl::OkStatus();
256 }
257 // The TOS/TrafficClass byte consists of following bits:
258 // | 7 6 5 4 3 2 | 1 0 |
259 // | DSCP | ECN |
260 int value = dscp << 2;
261
262 int optval;
263 socklen_t optlen = sizeof(optval);
264 // Get ECN bits from current IP_TOS value unless IPv6 only
265 if (0 == getsockopt(fd, IPPROTO_IP, IP_TOS, &optval, &optlen)) {
266 value |= (optval & 0x3);
267 if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &value, sizeof(value))) {
268 return GRPC_OS_ERROR(errno, "setsockopt(IP_TOS)");
269 }
270 }
271 // Get ECN from current Traffic Class value if IPv6 is available
272 if (0 == getsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, &optlen)) {
273 value |= (optval & 0x3);
274 if (0 != setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &value, sizeof(value))) {
275 return GRPC_OS_ERROR(errno, "setsockopt(IPV6_TCLASS)");
276 }
277 }
278 return absl::OkStatus();
279 }
280
281 // The default values for TCP_USER_TIMEOUT are currently configured to be in
282 // line with the default values of KEEPALIVE_TIMEOUT as proposed in
283 // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md
284 #define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 // 20 seconds
285 #define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 // 20 seconds
286
287 static int g_default_client_tcp_user_timeout_ms =
288 DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
289 static int g_default_server_tcp_user_timeout_ms =
290 DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
291 static bool g_default_client_tcp_user_timeout_enabled = false;
292 static bool g_default_server_tcp_user_timeout_enabled = true;
293
294 #if GPR_LINUX == 1
295 // For Linux, it will be detected to support TCP_USER_TIMEOUT
296 #ifndef TCP_USER_TIMEOUT
297 #define TCP_USER_TIMEOUT 18
298 #endif
299 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT 0
300 #else
301 // For non-Linux, TCP_USER_TIMEOUT will be used if TCP_USER_TIMEOUT is defined.
302 #ifdef TCP_USER_TIMEOUT
303 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT 0
304 #else
305 #define TCP_USER_TIMEOUT 0
306 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT -1
307 #endif // TCP_USER_TIMEOUT
308 #endif // GPR_LINUX == 1
309
310 // Whether the socket supports TCP_USER_TIMEOUT option.
311 // (0: don't know, 1: support, -1: not support)
312 static std::atomic<int> g_socket_supports_tcp_user_timeout(
313 SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT);
314
config_default_tcp_user_timeout(bool enable,int timeout,bool is_client)315 void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
316 if (is_client) {
317 g_default_client_tcp_user_timeout_enabled = enable;
318 if (timeout > 0) {
319 g_default_client_tcp_user_timeout_ms = timeout;
320 }
321 } else {
322 g_default_server_tcp_user_timeout_enabled = enable;
323 if (timeout > 0) {
324 g_default_server_tcp_user_timeout_ms = timeout;
325 }
326 }
327 }
328
329 // Set TCP_USER_TIMEOUT
330 // As documented in
331 // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md, the
332 // default values for TCP_USER_TIMEOUT are currently configured to be in line
333 // with the default values of KEEPALIVE_TIMEOUT as proposed in
334 // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md. In
335 // other words, by default, TCP_USER_TIMEOUT is disabled on clients (since
336 // keepalive is disabled on clients by default), and enabled on servers. To
337 // override the default settings of enabling/disabling TCP_USER_TIMEOUT, the
338 // value of KEEPALIVE_TIME on channel args is used. If present, a value of
339 // INT_MAX means that TCP_USER_TIMEOUT would be disabled, while any other value
340 // would enable TCP_USER_TIMEOUT. If TCP_USER_TIMEOUT is enabled, the default
341 // setting is 20 seconds (aligning with the default of KEEPALIVE_TIMEOUT). The
342 // KEEPALIVE_TIMEOUT channel arg overrides the value used for TCP_USER_TIMEOUT.
grpc_set_socket_tcp_user_timeout(int fd,const grpc_core::PosixTcpOptions & options,bool is_client)343 grpc_error_handle grpc_set_socket_tcp_user_timeout(
344 int fd, const grpc_core::PosixTcpOptions& options, bool is_client) {
345 // Use conditionally-important parameter to avoid warning
346 (void)fd;
347 (void)is_client;
348 extern grpc_core::TraceFlag grpc_tcp_trace;
349 if (g_socket_supports_tcp_user_timeout.load() >= 0) {
350 bool enable;
351 int timeout;
352 if (is_client) {
353 enable = g_default_client_tcp_user_timeout_enabled;
354 timeout = g_default_client_tcp_user_timeout_ms;
355 } else {
356 enable = g_default_server_tcp_user_timeout_enabled;
357 timeout = g_default_server_tcp_user_timeout_ms;
358 }
359 int value = options.keep_alive_time_ms;
360 if (value > 0) {
361 enable = value != INT_MAX;
362 }
363 value = options.keep_alive_timeout_ms;
364 if (value > 0) {
365 timeout = value;
366 }
367 if (enable) {
368 int newval;
369 socklen_t len = sizeof(newval);
370 // If this is the first time to use TCP_USER_TIMEOUT, try to check
371 // if it is available.
372 if (g_socket_supports_tcp_user_timeout.load() == 0) {
373 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
374 gpr_log(GPR_INFO,
375 "TCP_USER_TIMEOUT is not available. TCP_USER_TIMEOUT won't "
376 "be used thereafter");
377 g_socket_supports_tcp_user_timeout.store(-1);
378 } else {
379 gpr_log(GPR_INFO,
380 "TCP_USER_TIMEOUT is available. TCP_USER_TIMEOUT will be "
381 "used thereafter");
382 g_socket_supports_tcp_user_timeout.store(1);
383 }
384 }
385 if (g_socket_supports_tcp_user_timeout.load() > 0) {
386 if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
387 gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
388 timeout);
389 }
390 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
391 sizeof(timeout))) {
392 gpr_log(GPR_ERROR, "setsockopt(TCP_USER_TIMEOUT) %s",
393 grpc_core::StrError(errno).c_str());
394 return absl::OkStatus();
395 }
396 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
397 gpr_log(GPR_ERROR, "getsockopt(TCP_USER_TIMEOUT) %s",
398 grpc_core::StrError(errno).c_str());
399 return absl::OkStatus();
400 }
401 if (newval != timeout) {
402 gpr_log(GPR_INFO,
403 "Setting TCP_USER_TIMEOUT to value %d ms. Actual "
404 "TCP_USER_TIMEOUT value is %d ms",
405 timeout, newval);
406 return absl::OkStatus();
407 }
408 }
409 }
410 } else {
411 if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
412 gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
413 }
414 }
415 return absl::OkStatus();
416 }
417
418 // set a socket using a grpc_socket_mutator
grpc_set_socket_with_mutator(int fd,grpc_fd_usage usage,grpc_socket_mutator * mutator)419 grpc_error_handle grpc_set_socket_with_mutator(int fd, grpc_fd_usage usage,
420 grpc_socket_mutator* mutator) {
421 GPR_ASSERT(mutator);
422 if (!grpc_socket_mutator_mutate_fd(mutator, fd, usage)) {
423 return GRPC_ERROR_CREATE("grpc_socket_mutator failed.");
424 }
425 return absl::OkStatus();
426 }
427
grpc_apply_socket_mutator_in_args(int fd,grpc_fd_usage usage,const grpc_core::PosixTcpOptions & options)428 grpc_error_handle grpc_apply_socket_mutator_in_args(
429 int fd, grpc_fd_usage usage, const grpc_core::PosixTcpOptions& options) {
430 if (options.socket_mutator == nullptr) {
431 return absl::OkStatus();
432 }
433 return grpc_set_socket_with_mutator(fd, usage, options.socket_mutator);
434 }
435
436 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
437 static int g_ipv6_loopback_available;
438
probe_ipv6_once(void)439 static void probe_ipv6_once(void) {
440 int fd = socket(AF_INET6, SOCK_STREAM, 0);
441 g_ipv6_loopback_available = 0;
442 if (fd < 0) {
443 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
444 } else {
445 grpc_sockaddr_in6 addr;
446 memset(&addr, 0, sizeof(addr));
447 addr.sin6_family = AF_INET6;
448 addr.sin6_addr.s6_addr[15] = 1; // [::1]:0
449 if (bind(fd, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
450 g_ipv6_loopback_available = 1;
451 } else {
452 gpr_log(GPR_INFO,
453 "Disabling AF_INET6 sockets because ::1 is not available.");
454 }
455 close(fd);
456 }
457 }
458
grpc_ipv6_loopback_available(void)459 int grpc_ipv6_loopback_available(void) {
460 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
461 return g_ipv6_loopback_available;
462 }
463
error_for_fd(int fd,const grpc_resolved_address * addr)464 static grpc_error_handle error_for_fd(int fd,
465 const grpc_resolved_address* addr) {
466 if (fd >= 0) return absl::OkStatus();
467 auto addr_str = grpc_sockaddr_to_string(addr, false);
468 grpc_error_handle err = grpc_error_set_str(
469 GRPC_OS_ERROR(errno, "socket"),
470 grpc_core::StatusStrProperty::kTargetAddress,
471 addr_str.ok() ? addr_str.value() : addr_str.status().ToString());
472 return err;
473 }
474
grpc_create_dualstack_socket(const grpc_resolved_address * resolved_addr,int type,int protocol,grpc_dualstack_mode * dsmode,int * newfd)475 grpc_error_handle grpc_create_dualstack_socket(
476 const grpc_resolved_address* resolved_addr, int type, int protocol,
477 grpc_dualstack_mode* dsmode, int* newfd) {
478 return grpc_create_dualstack_socket_using_factory(
479 nullptr, resolved_addr, type, protocol, dsmode, newfd);
480 }
481
create_socket(grpc_socket_factory * factory,int domain,int type,int protocol)482 static int create_socket(grpc_socket_factory* factory, int domain, int type,
483 int protocol) {
484 int res = (factory != nullptr)
485 ? grpc_socket_factory_socket(factory, domain, type, protocol)
486 : socket(domain, type, protocol);
487 if (res < 0 && errno == EMFILE) {
488 int saved_errno = errno;
489 GRPC_LOG_EVERY_N_SEC(
490 10, GPR_ERROR,
491 "socket(%d, %d, %d) returned %d with error: |%s|. This process "
492 "might not have a sufficient file descriptor limit for the number "
493 "of connections grpc wants to open (which is generally a function of "
494 "the number of grpc channels, the lb policy of each channel, and the "
495 "number of backends each channel is load balancing across).",
496 domain, type, protocol, res, grpc_core::StrError(errno).c_str());
497 errno = saved_errno;
498 }
499 return res;
500 }
501
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)502 grpc_error_handle grpc_create_dualstack_socket_using_factory(
503 grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
504 int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
505 const grpc_sockaddr* addr =
506 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
507 int family = addr->sa_family;
508 if (family == AF_INET6) {
509 if (grpc_ipv6_loopback_available()) {
510 *newfd = create_socket(factory, family, type, protocol);
511 } else {
512 *newfd = -1;
513 errno = EAFNOSUPPORT;
514 }
515 // Check if we've got a valid dualstack socket.
516 if (*newfd >= 0 && grpc_set_socket_dualstack(*newfd)) {
517 *dsmode = GRPC_DSMODE_DUALSTACK;
518 return absl::OkStatus();
519 }
520 // If this isn't an IPv4 address, then return whatever we've got.
521 if (!grpc_sockaddr_is_v4mapped(resolved_addr, nullptr)) {
522 *dsmode = GRPC_DSMODE_IPV6;
523 return error_for_fd(*newfd, resolved_addr);
524 }
525 // Fall back to AF_INET.
526 if (*newfd >= 0) {
527 close(*newfd);
528 }
529 family = AF_INET;
530 }
531 *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
532 *newfd = create_socket(factory, family, type, protocol);
533 return error_for_fd(*newfd, resolved_addr);
534 }
535
536 #endif
537