summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/src/anet.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/src/anet.c')
-rw-r--r--examples/redis-unstable/src/anet.c812
1 files changed, 812 insertions, 0 deletions
diff --git a/examples/redis-unstable/src/anet.c b/examples/redis-unstable/src/anet.c
new file mode 100644
index 0000000..8b7b91e
--- /dev/null
+++ b/examples/redis-unstable/src/anet.c
@@ -0,0 +1,812 @@
1/* anet.c -- Basic TCP socket stuff made a bit less boring
2 *
3 * Copyright (c) 2006-Present, Redis Ltd.
4 * All rights reserved.
5 *
6 * Licensed under your choice of (a) the Redis Source Available License 2.0
7 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
8 * GNU Affero General Public License v3 (AGPLv3).
9 */
10
11#include "fmacros.h"
12
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <sys/stat.h>
16#include <sys/un.h>
17#include <sys/time.h>
18#include <netinet/in.h>
19#include <netinet/tcp.h>
20#include <arpa/inet.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <string.h>
24#include <netdb.h>
25#include <errno.h>
26#include <stdarg.h>
27#include <stdio.h>
28
29#include "anet.h"
30#include "config.h"
31#include "util.h"
32
33#define UNUSED(x) (void)(x)
34
35static void anetSetError(char *err, const char *fmt, ...)
36{
37 va_list ap;
38
39 if (!err) return;
40 va_start(ap, fmt);
41 vsnprintf(err, ANET_ERR_LEN, fmt, ap);
42 va_end(ap);
43}
44
45int anetGetError(int fd) {
46 int sockerr = 0;
47 socklen_t errlen = sizeof(sockerr);
48
49 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) == -1)
50 sockerr = errno;
51 return sockerr;
52}
53
54int anetSetBlock(char *err, int fd, int non_block) {
55 int flags;
56
57 /* Set the socket blocking (if non_block is zero) or non-blocking.
58 * Note that fcntl(2) for F_GETFL and F_SETFL can't be
59 * interrupted by a signal. */
60 if ((flags = fcntl(fd, F_GETFL)) == -1) {
61 anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
62 return ANET_ERR;
63 }
64
65 /* Check if this flag has been set or unset, if so,
66 * then there is no need to call fcntl to set/unset it again. */
67 if (!!(flags & O_NONBLOCK) == !!non_block)
68 return ANET_OK;
69
70 if (non_block)
71 flags |= O_NONBLOCK;
72 else
73 flags &= ~O_NONBLOCK;
74
75 if (fcntl(fd, F_SETFL, flags) == -1) {
76 anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
77 return ANET_ERR;
78 }
79 return ANET_OK;
80}
81
82int anetNonBlock(char *err, int fd) {
83 return anetSetBlock(err,fd,1);
84}
85
86int anetBlock(char *err, int fd) {
87 return anetSetBlock(err,fd,0);
88}
89
90/* Enable the FD_CLOEXEC on the given fd to avoid fd leaks.
91 * This function should be invoked for fd's on specific places
92 * where fork + execve system calls are called. */
93int anetCloexec(int fd) {
94 int r;
95 int flags;
96
97 do {
98 r = fcntl(fd, F_GETFD);
99 } while (r == -1 && errno == EINTR);
100
101 if (r == -1 || (r & FD_CLOEXEC))
102 return r;
103
104 flags = r | FD_CLOEXEC;
105
106 do {
107 r = fcntl(fd, F_SETFD, flags);
108 } while (r == -1 && errno == EINTR);
109
110 return r;
111}
112
113/* Enable TCP keep-alive mechanism to detect dead peers,
114 * TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT will be set accordingly. */
115int anetKeepAlive(char *err, int fd, int interval)
116{
117 int enabled = 1;
118 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enabled, sizeof(enabled)))
119 {
120 anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
121 return ANET_ERR;
122 }
123
124 int idle;
125 int intvl;
126 int cnt;
127
128 /* There are platforms that are expected to support the full mechanism of TCP keep-alive,
129 * we want the compiler to emit warnings of unused variables if the preprocessor directives
130 * somehow fail, and other than those platforms, just omit these warnings if they happen.
131 */
132#if !(defined(_AIX) || defined(__APPLE__) || defined(__DragonFly__) || \
133 defined(__FreeBSD__) || defined(__illumos__) || defined(__linux__) || \
134 defined(__NetBSD__) || defined(__sun))
135 UNUSED(interval);
136 UNUSED(idle);
137 UNUSED(intvl);
138 UNUSED(cnt);
139#endif
140
141#ifdef __sun
142 /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
143 * compared to other Unix-like systems.
144 * Thus, we need to specialize it on Solaris.
145 *
146 * There are two keep-alive mechanisms on Solaris:
147 * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours.
148 * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted.
149 * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD
150 * in milliseconds or TCP_KEEPIDLE in seconds.
151 * The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds.
152 * The maximum is ten days, while the default is two hours. If you receive no response to the probe,
153 * you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection.
154 * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and
155 * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval.
156 * The default is eight minutes.
157 *
158 * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set.
159 * The time between each consequent probes is set by TCP_KEEPINTVL in seconds.
160 * The minimum value is ten seconds. The maximum is ten days, while the default is two hours.
161 * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response.
162 */
163
164 idle = interval;
165 if (idle < 10) idle = 10; // kernel expects at least 10 seconds
166 if (idle > 10*24*60*60) idle = 10*24*60*60; // kernel expects at most 10 days
167
168 /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris
169 * until version 11.4, but let's take a chance here. */
170#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
171 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) {
172 anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno));
173 return ANET_ERR;
174 }
175
176 intvl = idle/3;
177 if (intvl < 10) intvl = 10; /* kernel expects at least 10 seconds */
178 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) {
179 anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno));
180 return ANET_ERR;
181 }
182
183 cnt = 3;
184 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) {
185 anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
186 return ANET_ERR;
187 }
188#else
189 /* Fall back to the first implementation of tcp-alive mechanism for older Solaris,
190 * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
191 */
192 idle *= 1000; // kernel expects milliseconds
193 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) {
194 anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno));
195 return ANET_ERR;
196 }
197
198 /* Note that the consequent probes will not be sent at equal intervals on Solaris,
199 * but will be sent using the exponential backoff algorithm. */
200 int time_to_abort = idle;
201 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) {
202 anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
203 return ANET_ERR;
204 }
205#endif
206
207 return ANET_OK;
208
209#endif
210
211#ifdef TCP_KEEPIDLE
212 /* Default settings are more or less garbage, with the keepalive time
213 * set to 7200 by default on Linux and other Unix-like systems.
214 * Modify settings to make the feature actually useful. */
215
216 /* Send first probe after interval. */
217 idle = interval;
218 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) {
219 anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno));
220 return ANET_ERR;
221 }
222#elif defined(TCP_KEEPALIVE)
223 /* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
224 idle = interval;
225 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle))) {
226 anetSetError(err, "setsockopt TCP_KEEPALIVE: %s\n", strerror(errno));
227 return ANET_ERR;
228 }
229#endif
230
231#ifdef TCP_KEEPINTVL
232 /* Send next probes after the specified interval. Note that we set the
233 * delay as interval / 3, as we send three probes before detecting
234 * an error (see the next setsockopt call). */
235 intvl = interval/3;
236 if (intvl == 0) intvl = 1;
237 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) {
238 anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno));
239 return ANET_ERR;
240 }
241#endif
242
243#ifdef TCP_KEEPCNT
244 /* Consider the socket in error state after three we send three ACK
245 * probes without getting a reply. */
246 cnt = 3;
247 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) {
248 anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
249 return ANET_ERR;
250 }
251#endif
252
253 return ANET_OK;
254}
255
256static int anetSetTcpNoDelay(char *err, int fd, int val)
257{
258 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1)
259 {
260 anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
261 return ANET_ERR;
262 }
263 return ANET_OK;
264}
265
266int anetEnableTcpNoDelay(char *err, int fd)
267{
268 return anetSetTcpNoDelay(err, fd, 1);
269}
270
271int anetDisableTcpNoDelay(char *err, int fd)
272{
273 return anetSetTcpNoDelay(err, fd, 0);
274}
275
276/* Set the socket send timeout (SO_SNDTIMEO socket option) to the specified
277 * number of milliseconds, or disable it if the 'ms' argument is zero. */
278int anetSendTimeout(char *err, int fd, long long ms) {
279 struct timeval tv;
280
281 tv.tv_sec = ms/1000;
282 tv.tv_usec = (ms%1000)*1000;
283 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
284 anetSetError(err, "setsockopt SO_SNDTIMEO: %s", strerror(errno));
285 return ANET_ERR;
286 }
287 return ANET_OK;
288}
289
290/* Set the socket receive timeout (SO_RCVTIMEO socket option) to the specified
291 * number of milliseconds, or disable it if the 'ms' argument is zero. */
292int anetRecvTimeout(char *err, int fd, long long ms) {
293 struct timeval tv;
294
295 tv.tv_sec = ms/1000;
296 tv.tv_usec = (ms%1000)*1000;
297 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
298 anetSetError(err, "setsockopt SO_RCVTIMEO: %s", strerror(errno));
299 return ANET_ERR;
300 }
301 return ANET_OK;
302}
303
304/* Resolve the hostname "host" and set the string representation of the
305 * IP address into the buffer pointed by "ipbuf".
306 *
307 * If flags is set to ANET_IP_ONLY the function only resolves hostnames
308 * that are actually already IPv4 or IPv6 addresses. This turns the function
309 * into a validating / normalizing function.
310 *
311 * If the flag ANET_PREFER_IPV4 is set, IPv4 is preferred over IPv6.
312 * If the flag ANET_PREFER_IPV6 is set, IPv6 is preferred over IPv4.
313 * */
314int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len,
315 int flags)
316{
317 struct addrinfo hints, *info;
318 int rv;
319
320 memset(&hints,0,sizeof(hints));
321 if (flags & ANET_IP_ONLY) hints.ai_flags = AI_NUMERICHOST;
322 hints.ai_family = AF_UNSPEC;
323 if (flags & ANET_PREFER_IPV4 && !(flags & ANET_PREFER_IPV6)) {
324 hints.ai_family = AF_INET;
325 } else if (flags & ANET_PREFER_IPV6 && !(flags & ANET_PREFER_IPV4)) {
326 hints.ai_family = AF_INET6;
327 }
328 hints.ai_socktype = SOCK_STREAM; /* specify socktype to avoid dups */
329
330 rv = getaddrinfo(host, NULL, &hints, &info);
331 if (rv != 0 && hints.ai_family != AF_UNSPEC) {
332 /* Try the other IP version. */
333 hints.ai_family = (hints.ai_family == AF_INET) ? AF_INET6 : AF_INET;
334 rv = getaddrinfo(host, NULL, &hints, &info);
335 }
336 if (rv != 0) {
337 anetSetError(err, "%s", gai_strerror(rv));
338 return ANET_ERR;
339 }
340 if (info->ai_family == AF_INET) {
341 struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr;
342 inet_ntop(AF_INET, &(sa->sin_addr), ipbuf, ipbuf_len);
343 } else {
344 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)info->ai_addr;
345 inet_ntop(AF_INET6, &(sa->sin6_addr), ipbuf, ipbuf_len);
346 }
347
348 freeaddrinfo(info);
349 return ANET_OK;
350}
351
352static int anetSetReuseAddr(char *err, int fd) {
353 int yes = 1;
354 /* Make sure connection-intensive things like the redis benchmark
355 * will be able to close/open sockets a zillion of times */
356 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
357 anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
358 return ANET_ERR;
359 }
360 return ANET_OK;
361}
362
363static int anetCreateSocket(char *err, int domain) {
364 int s;
365 if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
366 anetSetError(err, "creating socket: %s", strerror(errno));
367 return ANET_ERR;
368 }
369
370 /* Make sure connection-intensive things like the redis benchmark
371 * will be able to close/open sockets a zillion of times */
372 if (anetSetReuseAddr(err,s) == ANET_ERR) {
373 close(s);
374 return ANET_ERR;
375 }
376 return s;
377}
378
379#define ANET_CONNECT_NONE 0
380#define ANET_CONNECT_NONBLOCK 1
381#define ANET_CONNECT_BE_BINDING 2 /* Best effort binding. */
382static int anetTcpGenericConnect(char *err, const char *addr, int port,
383 const char *source_addr, int flags)
384{
385 int s = ANET_ERR, rv;
386 char portstr[6]; /* strlen("65535") + 1; */
387 struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
388
389 snprintf(portstr,sizeof(portstr),"%d",port);
390 memset(&hints,0,sizeof(hints));
391 hints.ai_family = AF_UNSPEC;
392 hints.ai_socktype = SOCK_STREAM;
393
394 if ((rv = getaddrinfo(addr,portstr,&hints,&servinfo)) != 0) {
395 anetSetError(err, "%s", gai_strerror(rv));
396 return ANET_ERR;
397 }
398 for (p = servinfo; p != NULL; p = p->ai_next) {
399 /* Try to create the socket and to connect it.
400 * If we fail in the socket() call, or on connect(), we retry with
401 * the next entry in servinfo. */
402 if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
403 continue;
404 if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
405 if (flags & ANET_CONNECT_NONBLOCK && anetNonBlock(err,s) != ANET_OK)
406 goto error;
407 if (source_addr) {
408 int bound = 0;
409 /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
410 if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0)
411 {
412 anetSetError(err, "%s", gai_strerror(rv));
413 goto error;
414 }
415 for (b = bservinfo; b != NULL; b = b->ai_next) {
416 if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
417 bound = 1;
418 break;
419 }
420 }
421 freeaddrinfo(bservinfo);
422 if (!bound) {
423 anetSetError(err, "bind: %s", strerror(errno));
424 goto error;
425 }
426 }
427 if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
428 /* If the socket is non-blocking, it is ok for connect() to
429 * return an EINPROGRESS error here. */
430 if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK)
431 goto end;
432 close(s);
433 s = ANET_ERR;
434 continue;
435 }
436
437 /* If we ended an iteration of the for loop without errors, we
438 * have a connected socket. Let's return to the caller. */
439 goto end;
440 }
441 if (p == NULL)
442 anetSetError(err, "creating socket: %s", strerror(errno));
443
444error:
445 if (s != ANET_ERR) {
446 close(s);
447 s = ANET_ERR;
448 }
449
450end:
451 freeaddrinfo(servinfo);
452
453 /* Handle best effort binding: if a binding address was used, but it is
454 * not possible to create a socket, try again without a binding address. */
455 if (s == ANET_ERR && source_addr && (flags & ANET_CONNECT_BE_BINDING)) {
456 return anetTcpGenericConnect(err,addr,port,NULL,flags);
457 } else {
458 return s;
459 }
460}
461
462int anetTcpNonBlockConnect(char *err, const char *addr, int port)
463{
464 return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONBLOCK);
465}
466
467int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
468 const char *source_addr)
469{
470 return anetTcpGenericConnect(err,addr,port,source_addr,
471 ANET_CONNECT_NONBLOCK|ANET_CONNECT_BE_BINDING);
472}
473
474int anetUnixGenericConnect(char *err, const char *path, int flags)
475{
476 int s;
477 struct sockaddr_un sa;
478
479 if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
480 return ANET_ERR;
481
482 sa.sun_family = AF_LOCAL;
483 redis_strlcpy(sa.sun_path,path,sizeof(sa.sun_path));
484 if (flags & ANET_CONNECT_NONBLOCK) {
485 if (anetNonBlock(err,s) != ANET_OK) {
486 close(s);
487 return ANET_ERR;
488 }
489 }
490 if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
491 if (errno == EINPROGRESS &&
492 flags & ANET_CONNECT_NONBLOCK)
493 return s;
494
495 anetSetError(err, "connect: %s", strerror(errno));
496 close(s);
497 return ANET_ERR;
498 }
499 return s;
500}
501
502static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog, mode_t perm) {
503 if (bind(s,sa,len) == -1) {
504 anetSetError(err, "bind: %s", strerror(errno));
505 close(s);
506 return ANET_ERR;
507 }
508
509 if (sa->sa_family == AF_LOCAL && perm)
510 chmod(((struct sockaddr_un *) sa)->sun_path, perm);
511
512 if (listen(s, backlog) == -1) {
513 anetSetError(err, "listen: %s", strerror(errno));
514 close(s);
515 return ANET_ERR;
516 }
517 return ANET_OK;
518}
519
520static int anetV6Only(char *err, int s) {
521 int yes = 1;
522 if (setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes)) == -1) {
523 anetSetError(err, "setsockopt: %s", strerror(errno));
524 return ANET_ERR;
525 }
526 return ANET_OK;
527}
528
529static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog)
530{
531 int s = -1, rv;
532 char _port[6]; /* strlen("65535") */
533 struct addrinfo hints, *servinfo, *p;
534
535 snprintf(_port,6,"%d",port);
536 memset(&hints,0,sizeof(hints));
537 hints.ai_family = af;
538 hints.ai_socktype = SOCK_STREAM;
539 hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */
540 if (bindaddr && !strcmp("*", bindaddr))
541 bindaddr = NULL;
542 if (af == AF_INET6 && bindaddr && !strcmp("::*", bindaddr))
543 bindaddr = NULL;
544
545 if ((rv = getaddrinfo(bindaddr,_port,&hints,&servinfo)) != 0) {
546 anetSetError(err, "%s", gai_strerror(rv));
547 return ANET_ERR;
548 }
549 for (p = servinfo; p != NULL; p = p->ai_next) {
550 if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
551 continue;
552
553 if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
554 if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
555 if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog,0) == ANET_ERR) s = ANET_ERR;
556 goto end;
557 }
558 if (p == NULL) {
559 anetSetError(err, "unable to bind socket, errno: %d", errno);
560 goto error;
561 }
562
563error:
564 if (s != -1) close(s);
565 s = ANET_ERR;
566end:
567 freeaddrinfo(servinfo);
568 return s;
569}
570
571int anetTcpServer(char *err, int port, char *bindaddr, int backlog)
572{
573 return _anetTcpServer(err, port, bindaddr, AF_INET, backlog);
574}
575
576int anetTcp6Server(char *err, int port, char *bindaddr, int backlog)
577{
578 return _anetTcpServer(err, port, bindaddr, AF_INET6, backlog);
579}
580
581int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
582{
583 int s;
584 struct sockaddr_un sa;
585
586 if (strlen(path) > sizeof(sa.sun_path)-1) {
587 anetSetError(err,"unix socket path too long (%zu), must be under %zu", strlen(path), sizeof(sa.sun_path));
588 return ANET_ERR;
589 }
590 if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
591 return ANET_ERR;
592
593 memset(&sa,0,sizeof(sa));
594 sa.sun_family = AF_LOCAL;
595 redis_strlcpy(sa.sun_path,path,sizeof(sa.sun_path));
596 if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog,perm) == ANET_ERR)
597 return ANET_ERR;
598 return s;
599}
600
601/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
602 * returns the new socket FD, or -1 on error. */
603static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
604 int fd;
605 do {
606 /* Use the accept4() call on linux to simultaneously accept and
607 * set a socket as non-blocking. */
608#ifdef HAVE_ACCEPT4
609 fd = accept4(s, sa, len, SOCK_NONBLOCK | SOCK_CLOEXEC);
610#else
611 fd = accept(s,sa,len);
612#endif
613 } while(fd == -1 && errno == EINTR);
614 if (fd == -1) {
615 anetSetError(err, "accept: %s", strerror(errno));
616 return ANET_ERR;
617 }
618#ifndef HAVE_ACCEPT4
619 if (anetCloexec(fd) == -1) {
620 anetSetError(err, "anetCloexec: %s", strerror(errno));
621 close(fd);
622 return ANET_ERR;
623 }
624 if (anetNonBlock(err, fd) != ANET_OK) {
625 close(fd);
626 return ANET_ERR;
627 }
628#endif
629 return fd;
630}
631
632/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
633 * returns the new socket FD, or -1 on error. */
634int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port) {
635 int fd;
636 struct sockaddr_storage sa;
637 socklen_t salen = sizeof(sa);
638 if ((fd = anetGenericAccept(err,serversock,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
639 return ANET_ERR;
640
641 if (sa.ss_family == AF_INET) {
642 struct sockaddr_in *s = (struct sockaddr_in *)&sa;
643 if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
644 if (port) *port = ntohs(s->sin_port);
645 } else {
646 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
647 if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
648 if (port) *port = ntohs(s->sin6_port);
649 }
650 return fd;
651}
652
653/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
654 * returns the new socket FD, or -1 on error. */
655int anetUnixAccept(char *err, int s) {
656 int fd;
657 struct sockaddr_un sa;
658 socklen_t salen = sizeof(sa);
659 if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
660 return ANET_ERR;
661
662 return fd;
663}
664
665int anetFdToString(int fd, char *ip, size_t ip_len, int *port, int remote) {
666 struct sockaddr_storage sa;
667 socklen_t salen = sizeof(sa);
668
669 if (remote) {
670 if (getpeername(fd, (struct sockaddr *)&sa, &salen) == -1) goto error;
671 } else {
672 if (getsockname(fd, (struct sockaddr *)&sa, &salen) == -1) goto error;
673 }
674
675 if (sa.ss_family == AF_INET) {
676 struct sockaddr_in *s = (struct sockaddr_in *)&sa;
677 if (ip) {
678 if (inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len) == NULL)
679 goto error;
680 }
681 if (port) *port = ntohs(s->sin_port);
682 } else if (sa.ss_family == AF_INET6) {
683 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
684 if (ip) {
685 if (inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len) == NULL)
686 goto error;
687 }
688 if (port) *port = ntohs(s->sin6_port);
689 } else if (sa.ss_family == AF_UNIX) {
690 if (ip) {
691 int res = snprintf(ip, ip_len, "/unixsocket");
692 if (res < 0 || (unsigned int) res >= ip_len) goto error;
693 }
694 if (port) *port = 0;
695 } else {
696 goto error;
697 }
698 return 0;
699
700error:
701 if (ip) {
702 if (ip_len >= 2) {
703 ip[0] = '?';
704 ip[1] = '\0';
705 } else if (ip_len == 1) {
706 ip[0] = '\0';
707 }
708 }
709 if (port) *port = 0;
710 return -1;
711}
712
713/* Create a pipe buffer with given flags for read end and write end.
714 * Note that it supports the file flags defined by pipe2() and fcntl(F_SETFL),
715 * and one of the use cases is O_CLOEXEC|O_NONBLOCK. */
716int anetPipe(int fds[2], int read_flags, int write_flags) {
717 int pipe_flags = 0;
718#if defined(__linux__) || defined(__FreeBSD__)
719 /* When possible, try to leverage pipe2() to apply flags that are common to both ends.
720 * There is no harm to set O_CLOEXEC to prevent fd leaks. */
721 pipe_flags = O_CLOEXEC | (read_flags & write_flags);
722 if (pipe2(fds, pipe_flags)) {
723 /* Fail on real failures, and fallback to simple pipe if pipe2 is unsupported. */
724 if (errno != ENOSYS && errno != EINVAL)
725 return -1;
726 pipe_flags = 0;
727 } else {
728 /* If the flags on both ends are identical, no need to do anything else. */
729 if ((O_CLOEXEC | read_flags) == (O_CLOEXEC | write_flags))
730 return 0;
731 /* Clear the flags which have already been set using pipe2. */
732 read_flags &= ~pipe_flags;
733 write_flags &= ~pipe_flags;
734 }
735#endif
736
737 /* When we reach here with pipe_flags of 0, it means pipe2 failed (or was not attempted),
738 * so we try to use pipe. Otherwise, we skip and proceed to set specific flags below. */
739 if (pipe_flags == 0 && pipe(fds))
740 return -1;
741
742 /* File descriptor flags.
743 * Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. */
744 if (read_flags & O_CLOEXEC)
745 if (fcntl(fds[0], F_SETFD, FD_CLOEXEC))
746 goto error;
747 if (write_flags & O_CLOEXEC)
748 if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
749 goto error;
750
751 /* File status flags after clearing the file descriptor flag O_CLOEXEC. */
752 read_flags &= ~O_CLOEXEC;
753 if (read_flags)
754 if (fcntl(fds[0], F_SETFL, read_flags))
755 goto error;
756 write_flags &= ~O_CLOEXEC;
757 if (write_flags)
758 if (fcntl(fds[1], F_SETFL, write_flags))
759 goto error;
760
761 return 0;
762
763error:
764 close(fds[0]);
765 close(fds[1]);
766 return -1;
767}
768
769int anetSetSockMarkId(char *err, int fd, uint32_t id) {
770#ifdef HAVE_SOCKOPTMARKID
771 if (setsockopt(fd, SOL_SOCKET, SOCKOPTMARKID, (void *)&id, sizeof(id)) == -1) {
772 anetSetError(err, "setsockopt: %s", strerror(errno));
773 return ANET_ERR;
774 }
775 return ANET_OK;
776#else
777 UNUSED(fd);
778 UNUSED(id);
779 anetSetError(err,"anetSetSockMarkid unsupported on this platform");
780 return ANET_OK;
781#endif
782}
783
784int anetIsFifo(char *filepath) {
785 struct stat sb;
786 if (stat(filepath, &sb) == -1) return 0;
787 return S_ISFIFO(sb.st_mode);
788}
789
790/* This function must be called after accept4() fails. It returns 1 if 'err'
791 * indicates accepted connection faced an error, and it's okay to continue
792 * accepting next connection by calling accept4() again. Other errors either
793 * indicate programming errors, e.g. calling accept() on a closed fd or indicate
794 * a resource limit has been reached, e.g. -EMFILE, open fd limit has been
795 * reached. In the latter case, caller might wait until resources are available.
796 * See accept4() documentation for details. */
797int anetAcceptFailureNeedsRetry(int err) {
798 if (err == ECONNABORTED)
799 return 1;
800
801#if defined(__linux__)
802 /* For details, see 'Error Handling' section on
803 * https://man7.org/linux/man-pages/man2/accept.2.html */
804 if (err == ENETDOWN || err == EPROTO || err == ENOPROTOOPT ||
805 err == EHOSTDOWN || err == ENONET || err == EHOSTUNREACH ||
806 err == EOPNOTSUPP || err == ENETUNREACH)
807 {
808 return 1;
809 }
810#endif
811 return 0;
812}