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
263 #if GPR_LINUX == 1
264 // For Linux, it will be detected to support TCP_USER_TIMEOUT
265 #ifndef TCP_USER_TIMEOUT
266 #define TCP_USER_TIMEOUT 18
267 #endif
268 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT 0
269 #else
270 // For non-Linux, TCP_USER_TIMEOUT will be used if TCP_USER_TIMEOUT is defined.
271 #ifdef TCP_USER_TIMEOUT
272 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT 0
273 #else
274 #define TCP_USER_TIMEOUT 0
275 #define SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT -1
276 #endif // TCP_USER_TIMEOUT
277 #endif // GPR_LINUX == 1
278
279 // Whether the socket supports TCP_USER_TIMEOUT option.
280 // (0: don't know, 1: support, -1: not support)
281 static std::atomic<int> g_socket_supports_tcp_user_timeout(
282 SOCKET_SUPPORTS_TCP_USER_TIMEOUT_DEFAULT);
283
config_default_tcp_user_timeout(bool enable,int timeout,bool is_client)284 void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
285 if (is_client) {
286 g_default_client_tcp_user_timeout_enabled = enable;
287 if (timeout > 0) {
288 g_default_client_tcp_user_timeout_ms = timeout;
289 }
290 } else {
291 g_default_server_tcp_user_timeout_enabled = enable;
292 if (timeout > 0) {
293 g_default_server_tcp_user_timeout_ms = timeout;
294 }
295 }
296 }
297
298 /* Set TCP_USER_TIMEOUT */
grpc_set_socket_tcp_user_timeout(int fd,const grpc_channel_args * channel_args,bool is_client)299 grpc_error* grpc_set_socket_tcp_user_timeout(
300 int fd, const grpc_channel_args* channel_args, bool is_client) {
301 // Use conditionally-important parameter to avoid warning
302 (void)fd;
303 (void)channel_args;
304 (void)is_client;
305 extern grpc_core::TraceFlag grpc_tcp_trace;
306 if (g_socket_supports_tcp_user_timeout.load() >= 0) {
307 bool enable;
308 int timeout;
309 if (is_client) {
310 enable = g_default_client_tcp_user_timeout_enabled;
311 timeout = g_default_client_tcp_user_timeout_ms;
312 } else {
313 enable = g_default_server_tcp_user_timeout_enabled;
314 timeout = g_default_server_tcp_user_timeout_ms;
315 }
316 if (channel_args) {
317 for (unsigned int i = 0; i < channel_args->num_args; i++) {
318 if (0 ==
319 strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
320 const int value = grpc_channel_arg_get_integer(
321 &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
322 /* Continue using default if value is 0 */
323 if (value == 0) {
324 continue;
325 }
326 /* Disable if value is INT_MAX */
327 enable = value != INT_MAX;
328 } else if (0 == strcmp(channel_args->args[i].key,
329 GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
330 const int value = grpc_channel_arg_get_integer(
331 &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
332 /* Continue using default if value is 0 */
333 if (value == 0) {
334 continue;
335 }
336 timeout = value;
337 }
338 }
339 }
340 if (enable) {
341 int newval;
342 socklen_t len = sizeof(newval);
343 // If this is the first time to use TCP_USER_TIMEOUT, try to check
344 // if it is available.
345 if (g_socket_supports_tcp_user_timeout.load() == 0) {
346 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
347 gpr_log(GPR_INFO,
348 "TCP_USER_TIMEOUT is not available. TCP_USER_TIMEOUT won't "
349 "be used thereafter");
350 g_socket_supports_tcp_user_timeout.store(-1);
351 } else {
352 gpr_log(GPR_INFO,
353 "TCP_USER_TIMEOUT is available. TCP_USER_TIMEOUT will be "
354 "used thereafter");
355 g_socket_supports_tcp_user_timeout.store(1);
356 }
357 }
358 if (g_socket_supports_tcp_user_timeout.load() > 0) {
359 if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
360 gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
361 timeout);
362 }
363 if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
364 sizeof(timeout))) {
365 gpr_log(GPR_ERROR, "setsockopt(TCP_USER_TIMEOUT) %s",
366 strerror(errno));
367 return GRPC_ERROR_NONE;
368 }
369 if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
370 gpr_log(GPR_ERROR, "getsockopt(TCP_USER_TIMEOUT) %s",
371 strerror(errno));
372 return GRPC_ERROR_NONE;
373 }
374 if (newval != timeout) {
375 /* Do not fail on failing to set TCP_USER_TIMEOUT for now. */
376 gpr_log(GPR_ERROR, "Failed to set TCP_USER_TIMEOUT");
377 return GRPC_ERROR_NONE;
378 }
379 }
380 }
381 } else {
382 if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
383 gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
384 }
385 }
386 return GRPC_ERROR_NONE;
387 }
388
389 /* set a socket using a grpc_socket_mutator */
grpc_set_socket_with_mutator(int fd,grpc_socket_mutator * mutator)390 grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
391 GPR_ASSERT(mutator);
392 if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
393 return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed.");
394 }
395 return GRPC_ERROR_NONE;
396 }
397
grpc_apply_socket_mutator_in_args(int fd,const grpc_channel_args * args)398 grpc_error* grpc_apply_socket_mutator_in_args(int fd,
399 const grpc_channel_args* args) {
400 const grpc_arg* socket_mutator_arg =
401 grpc_channel_args_find(args, GRPC_ARG_SOCKET_MUTATOR);
402 if (socket_mutator_arg == nullptr) {
403 return GRPC_ERROR_NONE;
404 }
405 GPR_DEBUG_ASSERT(socket_mutator_arg->type == GRPC_ARG_POINTER);
406 grpc_socket_mutator* mutator =
407 static_cast<grpc_socket_mutator*>(socket_mutator_arg->value.pointer.p);
408 return grpc_set_socket_with_mutator(fd, mutator);
409 }
410
411 static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
412 static int g_ipv6_loopback_available;
413
probe_ipv6_once(void)414 static void probe_ipv6_once(void) {
415 int fd = socket(AF_INET6, SOCK_STREAM, 0);
416 g_ipv6_loopback_available = 0;
417 if (fd < 0) {
418 gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
419 } else {
420 grpc_sockaddr_in6 addr;
421 memset(&addr, 0, sizeof(addr));
422 addr.sin6_family = AF_INET6;
423 addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
424 if (bind(fd, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
425 g_ipv6_loopback_available = 1;
426 } else {
427 gpr_log(GPR_INFO,
428 "Disabling AF_INET6 sockets because ::1 is not available.");
429 }
430 close(fd);
431 }
432 }
433
grpc_ipv6_loopback_available(void)434 int grpc_ipv6_loopback_available(void) {
435 gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
436 return g_ipv6_loopback_available;
437 }
438
error_for_fd(int fd,const grpc_resolved_address * addr)439 static grpc_error* error_for_fd(int fd, const grpc_resolved_address* addr) {
440 if (fd >= 0) return GRPC_ERROR_NONE;
441 std::string addr_str = grpc_sockaddr_to_string(addr, false);
442 grpc_error* err = grpc_error_set_str(
443 GRPC_OS_ERROR(errno, "socket"), GRPC_ERROR_STR_TARGET_ADDRESS,
444 grpc_slice_from_copied_string(addr_str.c_str()));
445 return err;
446 }
447
grpc_create_dualstack_socket(const grpc_resolved_address * resolved_addr,int type,int protocol,grpc_dualstack_mode * dsmode,int * newfd)448 grpc_error* grpc_create_dualstack_socket(
449 const grpc_resolved_address* resolved_addr, int type, int protocol,
450 grpc_dualstack_mode* dsmode, int* newfd) {
451 return grpc_create_dualstack_socket_using_factory(
452 nullptr, resolved_addr, type, protocol, dsmode, newfd);
453 }
454
create_socket(grpc_socket_factory * factory,int domain,int type,int protocol)455 static int create_socket(grpc_socket_factory* factory, int domain, int type,
456 int protocol) {
457 return (factory != nullptr)
458 ? grpc_socket_factory_socket(factory, domain, type, protocol)
459 : socket(domain, type, protocol);
460 }
461
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)462 grpc_error* grpc_create_dualstack_socket_using_factory(
463 grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
464 int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
465 const grpc_sockaddr* addr =
466 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
467 int family = addr->sa_family;
468 if (family == AF_INET6) {
469 if (grpc_ipv6_loopback_available()) {
470 *newfd = create_socket(factory, family, type, protocol);
471 } else {
472 *newfd = -1;
473 errno = EAFNOSUPPORT;
474 }
475 /* Check if we've got a valid dualstack socket. */
476 if (*newfd >= 0 && grpc_set_socket_dualstack(*newfd)) {
477 *dsmode = GRPC_DSMODE_DUALSTACK;
478 return GRPC_ERROR_NONE;
479 }
480 /* If this isn't an IPv4 address, then return whatever we've got. */
481 if (!grpc_sockaddr_is_v4mapped(resolved_addr, nullptr)) {
482 *dsmode = GRPC_DSMODE_IPV6;
483 return error_for_fd(*newfd, resolved_addr);
484 }
485 /* Fall back to AF_INET. */
486 if (*newfd >= 0) {
487 close(*newfd);
488 }
489 family = AF_INET;
490 }
491 *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
492 *newfd = create_socket(factory, family, type, protocol);
493 return error_for_fd(*newfd, resolved_addr);
494 }
495
grpc_htons(uint16_t hostshort)496 uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
497
grpc_ntohs(uint16_t netshort)498 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
499
grpc_htonl(uint32_t hostlong)500 uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
501
grpc_ntohl(uint32_t netlong)502 uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
503
grpc_inet_pton(int af,const char * src,void * dst)504 int grpc_inet_pton(int af, const char* src, void* dst) {
505 return inet_pton(af, src, dst);
506 }
507
grpc_inet_ntop(int af,const void * src,char * dst,size_t size)508 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
509 GPR_ASSERT(size <= (socklen_t)-1);
510 return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
511 }
512
513 #endif
514