1 | /* anet.c -- Basic TCP socket stuff made a bit less boring |
2 | * |
3 | * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com> |
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 met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright notice, |
10 | * this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * * Neither the name of Redis nor the names of its contributors may be used |
15 | * to endorse or promote products derived from this software without |
16 | * specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | * POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | #include "fmacros.h" |
32 | |
33 | #include <sys/types.h> |
34 | #include <sys/socket.h> |
35 | #include <sys/stat.h> |
36 | #include <sys/un.h> |
37 | #include <sys/time.h> |
38 | #include <netinet/in.h> |
39 | #include <netinet/tcp.h> |
40 | #include <arpa/inet.h> |
41 | #include <unistd.h> |
42 | #include <fcntl.h> |
43 | #include <string.h> |
44 | #include <netdb.h> |
45 | #include <errno.h> |
46 | #include <stdarg.h> |
47 | #include <stdio.h> |
48 | |
49 | #include "anet.h" |
50 | #include "config.h" |
51 | |
52 | #define UNUSED(x) (void)(x) |
53 | |
54 | static void anetSetError(char *err, const char *fmt, ...) |
55 | { |
56 | va_list ap; |
57 | |
58 | if (!err) return; |
59 | va_start(ap, fmt); |
60 | vsnprintf(err, ANET_ERR_LEN, fmt, ap); |
61 | va_end(ap); |
62 | } |
63 | |
64 | int anetSetBlock(char *err, int fd, int non_block) { |
65 | int flags; |
66 | |
67 | /* Set the socket blocking (if non_block is zero) or non-blocking. |
68 | * Note that fcntl(2) for F_GETFL and F_SETFL can't be |
69 | * interrupted by a signal. */ |
70 | if ((flags = fcntl(fd, F_GETFL)) == -1) { |
71 | anetSetError(err, "fcntl(F_GETFL): %s" , strerror(errno)); |
72 | return ANET_ERR; |
73 | } |
74 | |
75 | /* Check if this flag has been set or unset, if so, |
76 | * then there is no need to call fcntl to set/unset it again. */ |
77 | if (!!(flags & O_NONBLOCK) == !!non_block) |
78 | return ANET_OK; |
79 | |
80 | if (non_block) |
81 | flags |= O_NONBLOCK; |
82 | else |
83 | flags &= ~O_NONBLOCK; |
84 | |
85 | if (fcntl(fd, F_SETFL, flags) == -1) { |
86 | anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s" , strerror(errno)); |
87 | return ANET_ERR; |
88 | } |
89 | return ANET_OK; |
90 | } |
91 | |
92 | int anetNonBlock(char *err, int fd) { |
93 | return anetSetBlock(err,fd,1); |
94 | } |
95 | |
96 | int anetBlock(char *err, int fd) { |
97 | return anetSetBlock(err,fd,0); |
98 | } |
99 | |
100 | /* Enable the FD_CLOEXEC on the given fd to avoid fd leaks. |
101 | * This function should be invoked for fd's on specific places |
102 | * where fork + execve system calls are called. */ |
103 | int anetCloexec(int fd) { |
104 | int r; |
105 | int flags; |
106 | |
107 | do { |
108 | r = fcntl(fd, F_GETFD); |
109 | } while (r == -1 && errno == EINTR); |
110 | |
111 | if (r == -1 || (r & FD_CLOEXEC)) |
112 | return r; |
113 | |
114 | flags = r | FD_CLOEXEC; |
115 | |
116 | do { |
117 | r = fcntl(fd, F_SETFD, flags); |
118 | } while (r == -1 && errno == EINTR); |
119 | |
120 | return r; |
121 | } |
122 | |
123 | /* Set TCP keep alive option to detect dead peers. The interval option |
124 | * is only used for Linux as we are using Linux-specific APIs to set |
125 | * the probe send time, interval, and count. */ |
126 | int anetKeepAlive(char *err, int fd, int interval) |
127 | { |
128 | int val = 1; |
129 | |
130 | if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1) |
131 | { |
132 | anetSetError(err, "setsockopt SO_KEEPALIVE: %s" , strerror(errno)); |
133 | return ANET_ERR; |
134 | } |
135 | |
136 | #ifdef __linux__ |
137 | /* Default settings are more or less garbage, with the keepalive time |
138 | * set to 7200 by default on Linux. Modify settings to make the feature |
139 | * actually useful. */ |
140 | |
141 | /* Send first probe after interval. */ |
142 | val = interval; |
143 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { |
144 | anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n" , strerror(errno)); |
145 | return ANET_ERR; |
146 | } |
147 | |
148 | /* Send next probes after the specified interval. Note that we set the |
149 | * delay as interval / 3, as we send three probes before detecting |
150 | * an error (see the next setsockopt call). */ |
151 | val = interval/3; |
152 | if (val == 0) val = 1; |
153 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { |
154 | anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n" , strerror(errno)); |
155 | return ANET_ERR; |
156 | } |
157 | |
158 | /* Consider the socket in error state after three we send three ACK |
159 | * probes without getting a reply. */ |
160 | val = 3; |
161 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { |
162 | anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n" , strerror(errno)); |
163 | return ANET_ERR; |
164 | } |
165 | #elif defined(__APPLE__) |
166 | /* Set idle time with interval */ |
167 | val = interval; |
168 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) { |
169 | anetSetError(err, "setsockopt TCP_KEEPALIVE: %s\n" , strerror(errno)); |
170 | return ANET_ERR; |
171 | } |
172 | #else |
173 | ((void) interval); /* Avoid unused var warning for non Linux systems. */ |
174 | #endif |
175 | |
176 | return ANET_OK; |
177 | } |
178 | |
179 | static int anetSetTcpNoDelay(char *err, int fd, int val) |
180 | { |
181 | if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) |
182 | { |
183 | anetSetError(err, "setsockopt TCP_NODELAY: %s" , strerror(errno)); |
184 | return ANET_ERR; |
185 | } |
186 | return ANET_OK; |
187 | } |
188 | |
189 | int anetEnableTcpNoDelay(char *err, int fd) |
190 | { |
191 | return anetSetTcpNoDelay(err, fd, 1); |
192 | } |
193 | |
194 | int anetDisableTcpNoDelay(char *err, int fd) |
195 | { |
196 | return anetSetTcpNoDelay(err, fd, 0); |
197 | } |
198 | |
199 | /* Set the socket send timeout (SO_SNDTIMEO socket option) to the specified |
200 | * number of milliseconds, or disable it if the 'ms' argument is zero. */ |
201 | int anetSendTimeout(char *err, int fd, long long ms) { |
202 | struct timeval tv; |
203 | |
204 | tv.tv_sec = ms/1000; |
205 | tv.tv_usec = (ms%1000)*1000; |
206 | if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { |
207 | anetSetError(err, "setsockopt SO_SNDTIMEO: %s" , strerror(errno)); |
208 | return ANET_ERR; |
209 | } |
210 | return ANET_OK; |
211 | } |
212 | |
213 | /* Set the socket receive timeout (SO_RCVTIMEO socket option) to the specified |
214 | * number of milliseconds, or disable it if the 'ms' argument is zero. */ |
215 | int anetRecvTimeout(char *err, int fd, long long ms) { |
216 | struct timeval tv; |
217 | |
218 | tv.tv_sec = ms/1000; |
219 | tv.tv_usec = (ms%1000)*1000; |
220 | if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { |
221 | anetSetError(err, "setsockopt SO_RCVTIMEO: %s" , strerror(errno)); |
222 | return ANET_ERR; |
223 | } |
224 | return ANET_OK; |
225 | } |
226 | |
227 | /* Resolve the hostname "host" and set the string representation of the |
228 | * IP address into the buffer pointed by "ipbuf". |
229 | * |
230 | * If flags is set to ANET_IP_ONLY the function only resolves hostnames |
231 | * that are actually already IPv4 or IPv6 addresses. This turns the function |
232 | * into a validating / normalizing function. */ |
233 | int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len, |
234 | int flags) |
235 | { |
236 | struct addrinfo hints, *info; |
237 | int rv; |
238 | |
239 | memset(&hints,0,sizeof(hints)); |
240 | if (flags & ANET_IP_ONLY) hints.ai_flags = AI_NUMERICHOST; |
241 | hints.ai_family = AF_UNSPEC; |
242 | hints.ai_socktype = SOCK_STREAM; /* specify socktype to avoid dups */ |
243 | |
244 | if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) { |
245 | anetSetError(err, "%s" , gai_strerror(rv)); |
246 | return ANET_ERR; |
247 | } |
248 | if (info->ai_family == AF_INET) { |
249 | struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr; |
250 | inet_ntop(AF_INET, &(sa->sin_addr), ipbuf, ipbuf_len); |
251 | } else { |
252 | struct sockaddr_in6 *sa = (struct sockaddr_in6 *)info->ai_addr; |
253 | inet_ntop(AF_INET6, &(sa->sin6_addr), ipbuf, ipbuf_len); |
254 | } |
255 | |
256 | freeaddrinfo(info); |
257 | return ANET_OK; |
258 | } |
259 | |
260 | static int anetSetReuseAddr(char *err, int fd) { |
261 | int yes = 1; |
262 | /* Make sure connection-intensive things like the redis benchmark |
263 | * will be able to close/open sockets a zillion of times */ |
264 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { |
265 | anetSetError(err, "setsockopt SO_REUSEADDR: %s" , strerror(errno)); |
266 | return ANET_ERR; |
267 | } |
268 | return ANET_OK; |
269 | } |
270 | |
271 | static int anetCreateSocket(char *err, int domain) { |
272 | int s; |
273 | if ((s = socket(domain, SOCK_STREAM, 0)) == -1) { |
274 | anetSetError(err, "creating socket: %s" , strerror(errno)); |
275 | return ANET_ERR; |
276 | } |
277 | |
278 | /* Make sure connection-intensive things like the redis benchmark |
279 | * will be able to close/open sockets a zillion of times */ |
280 | if (anetSetReuseAddr(err,s) == ANET_ERR) { |
281 | close(s); |
282 | return ANET_ERR; |
283 | } |
284 | return s; |
285 | } |
286 | |
287 | #define ANET_CONNECT_NONE 0 |
288 | #define ANET_CONNECT_NONBLOCK 1 |
289 | #define ANET_CONNECT_BE_BINDING 2 /* Best effort binding. */ |
290 | static int anetTcpGenericConnect(char *err, const char *addr, int port, |
291 | const char *source_addr, int flags) |
292 | { |
293 | int s = ANET_ERR, rv; |
294 | char portstr[6]; /* strlen("65535") + 1; */ |
295 | struct addrinfo hints, *servinfo, *bservinfo, *p, *b; |
296 | |
297 | snprintf(portstr,sizeof(portstr),"%d" ,port); |
298 | memset(&hints,0,sizeof(hints)); |
299 | hints.ai_family = AF_UNSPEC; |
300 | hints.ai_socktype = SOCK_STREAM; |
301 | |
302 | if ((rv = getaddrinfo(addr,portstr,&hints,&servinfo)) != 0) { |
303 | anetSetError(err, "%s" , gai_strerror(rv)); |
304 | return ANET_ERR; |
305 | } |
306 | for (p = servinfo; p != NULL; p = p->ai_next) { |
307 | /* Try to create the socket and to connect it. |
308 | * If we fail in the socket() call, or on connect(), we retry with |
309 | * the next entry in servinfo. */ |
310 | if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) |
311 | continue; |
312 | if (anetSetReuseAddr(err,s) == ANET_ERR) goto error; |
313 | if (flags & ANET_CONNECT_NONBLOCK && anetNonBlock(err,s) != ANET_OK) |
314 | goto error; |
315 | if (source_addr) { |
316 | int bound = 0; |
317 | /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ |
318 | if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) |
319 | { |
320 | anetSetError(err, "%s" , gai_strerror(rv)); |
321 | goto error; |
322 | } |
323 | for (b = bservinfo; b != NULL; b = b->ai_next) { |
324 | if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { |
325 | bound = 1; |
326 | break; |
327 | } |
328 | } |
329 | freeaddrinfo(bservinfo); |
330 | if (!bound) { |
331 | anetSetError(err, "bind: %s" , strerror(errno)); |
332 | goto error; |
333 | } |
334 | } |
335 | if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { |
336 | /* If the socket is non-blocking, it is ok for connect() to |
337 | * return an EINPROGRESS error here. */ |
338 | if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) |
339 | goto end; |
340 | close(s); |
341 | s = ANET_ERR; |
342 | continue; |
343 | } |
344 | |
345 | /* If we ended an iteration of the for loop without errors, we |
346 | * have a connected socket. Let's return to the caller. */ |
347 | goto end; |
348 | } |
349 | if (p == NULL) |
350 | anetSetError(err, "creating socket: %s" , strerror(errno)); |
351 | |
352 | error: |
353 | if (s != ANET_ERR) { |
354 | close(s); |
355 | s = ANET_ERR; |
356 | } |
357 | |
358 | end: |
359 | freeaddrinfo(servinfo); |
360 | |
361 | /* Handle best effort binding: if a binding address was used, but it is |
362 | * not possible to create a socket, try again without a binding address. */ |
363 | if (s == ANET_ERR && source_addr && (flags & ANET_CONNECT_BE_BINDING)) { |
364 | return anetTcpGenericConnect(err,addr,port,NULL,flags); |
365 | } else { |
366 | return s; |
367 | } |
368 | } |
369 | |
370 | int anetTcpNonBlockConnect(char *err, const char *addr, int port) |
371 | { |
372 | return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONBLOCK); |
373 | } |
374 | |
375 | int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port, |
376 | const char *source_addr) |
377 | { |
378 | return anetTcpGenericConnect(err,addr,port,source_addr, |
379 | ANET_CONNECT_NONBLOCK|ANET_CONNECT_BE_BINDING); |
380 | } |
381 | |
382 | int anetUnixGenericConnect(char *err, const char *path, int flags) |
383 | { |
384 | int s; |
385 | struct sockaddr_un sa; |
386 | |
387 | if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) |
388 | return ANET_ERR; |
389 | |
390 | sa.sun_family = AF_LOCAL; |
391 | strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); |
392 | if (flags & ANET_CONNECT_NONBLOCK) { |
393 | if (anetNonBlock(err,s) != ANET_OK) { |
394 | close(s); |
395 | return ANET_ERR; |
396 | } |
397 | } |
398 | if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) { |
399 | if (errno == EINPROGRESS && |
400 | flags & ANET_CONNECT_NONBLOCK) |
401 | return s; |
402 | |
403 | anetSetError(err, "connect: %s" , strerror(errno)); |
404 | close(s); |
405 | return ANET_ERR; |
406 | } |
407 | return s; |
408 | } |
409 | |
410 | static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) { |
411 | if (bind(s,sa,len) == -1) { |
412 | anetSetError(err, "bind: %s" , strerror(errno)); |
413 | close(s); |
414 | return ANET_ERR; |
415 | } |
416 | |
417 | if (listen(s, backlog) == -1) { |
418 | anetSetError(err, "listen: %s" , strerror(errno)); |
419 | close(s); |
420 | return ANET_ERR; |
421 | } |
422 | return ANET_OK; |
423 | } |
424 | |
425 | static int anetV6Only(char *err, int s) { |
426 | int yes = 1; |
427 | if (setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes)) == -1) { |
428 | anetSetError(err, "setsockopt: %s" , strerror(errno)); |
429 | return ANET_ERR; |
430 | } |
431 | return ANET_OK; |
432 | } |
433 | |
434 | static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog) |
435 | { |
436 | int s = -1, rv; |
437 | char _port[6]; /* strlen("65535") */ |
438 | struct addrinfo hints, *servinfo, *p; |
439 | |
440 | snprintf(_port,6,"%d" ,port); |
441 | memset(&hints,0,sizeof(hints)); |
442 | hints.ai_family = af; |
443 | hints.ai_socktype = SOCK_STREAM; |
444 | hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */ |
445 | if (bindaddr && !strcmp("*" , bindaddr)) |
446 | bindaddr = NULL; |
447 | if (af == AF_INET6 && bindaddr && !strcmp("::*" , bindaddr)) |
448 | bindaddr = NULL; |
449 | |
450 | if ((rv = getaddrinfo(bindaddr,_port,&hints,&servinfo)) != 0) { |
451 | anetSetError(err, "%s" , gai_strerror(rv)); |
452 | return ANET_ERR; |
453 | } |
454 | for (p = servinfo; p != NULL; p = p->ai_next) { |
455 | if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) |
456 | continue; |
457 | |
458 | if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error; |
459 | if (anetSetReuseAddr(err,s) == ANET_ERR) goto error; |
460 | if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) s = ANET_ERR; |
461 | goto end; |
462 | } |
463 | if (p == NULL) { |
464 | anetSetError(err, "unable to bind socket, errno: %d" , errno); |
465 | goto error; |
466 | } |
467 | |
468 | error: |
469 | if (s != -1) close(s); |
470 | s = ANET_ERR; |
471 | end: |
472 | freeaddrinfo(servinfo); |
473 | return s; |
474 | } |
475 | |
476 | int anetTcpServer(char *err, int port, char *bindaddr, int backlog) |
477 | { |
478 | return _anetTcpServer(err, port, bindaddr, AF_INET, backlog); |
479 | } |
480 | |
481 | int anetTcp6Server(char *err, int port, char *bindaddr, int backlog) |
482 | { |
483 | return _anetTcpServer(err, port, bindaddr, AF_INET6, backlog); |
484 | } |
485 | |
486 | int anetUnixServer(char *err, char *path, mode_t perm, int backlog) |
487 | { |
488 | int s; |
489 | struct sockaddr_un sa; |
490 | |
491 | if (strlen(path) > sizeof(sa.sun_path)-1) { |
492 | anetSetError(err,"unix socket path too long (%zu), must be under %zu" , strlen(path), sizeof(sa.sun_path)); |
493 | return ANET_ERR; |
494 | } |
495 | if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) |
496 | return ANET_ERR; |
497 | |
498 | memset(&sa,0,sizeof(sa)); |
499 | sa.sun_family = AF_LOCAL; |
500 | strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); |
501 | if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog) == ANET_ERR) |
502 | return ANET_ERR; |
503 | if (perm) |
504 | chmod(sa.sun_path, perm); |
505 | return s; |
506 | } |
507 | |
508 | /* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC. |
509 | * returns the new socket FD, or -1 on error. */ |
510 | static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) { |
511 | int fd; |
512 | do { |
513 | /* Use the accept4() call on linux to simultaneously accept and |
514 | * set a socket as non-blocking. */ |
515 | #ifdef HAVE_ACCEPT4 |
516 | fd = accept4(s, sa, len, SOCK_NONBLOCK | SOCK_CLOEXEC); |
517 | #else |
518 | fd = accept(s,sa,len); |
519 | #endif |
520 | } while(fd == -1 && errno == EINTR); |
521 | if (fd == -1) { |
522 | anetSetError(err, "accept: %s" , strerror(errno)); |
523 | return ANET_ERR; |
524 | } |
525 | #ifndef HAVE_ACCEPT4 |
526 | if (anetCloexec(fd) == -1) { |
527 | anetSetError(err, "anetCloexec: %s" , strerror(errno)); |
528 | close(fd); |
529 | return ANET_ERR; |
530 | } |
531 | if (anetNonBlock(err, fd) != ANET_OK) { |
532 | close(fd); |
533 | return ANET_ERR; |
534 | } |
535 | #endif |
536 | return fd; |
537 | } |
538 | |
539 | /* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC. |
540 | * returns the new socket FD, or -1 on error. */ |
541 | int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port) { |
542 | int fd; |
543 | struct sockaddr_storage sa; |
544 | socklen_t salen = sizeof(sa); |
545 | if ((fd = anetGenericAccept(err,serversock,(struct sockaddr*)&sa,&salen)) == ANET_ERR) |
546 | return ANET_ERR; |
547 | |
548 | if (sa.ss_family == AF_INET) { |
549 | struct sockaddr_in *s = (struct sockaddr_in *)&sa; |
550 | if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len); |
551 | if (port) *port = ntohs(s->sin_port); |
552 | } else { |
553 | struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa; |
554 | if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len); |
555 | if (port) *port = ntohs(s->sin6_port); |
556 | } |
557 | return fd; |
558 | } |
559 | |
560 | /* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC. |
561 | * returns the new socket FD, or -1 on error. */ |
562 | int anetUnixAccept(char *err, int s) { |
563 | int fd; |
564 | struct sockaddr_un sa; |
565 | socklen_t salen = sizeof(sa); |
566 | if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR) |
567 | return ANET_ERR; |
568 | |
569 | return fd; |
570 | } |
571 | |
572 | int anetFdToString(int fd, char *ip, size_t ip_len, int *port, int fd_to_str_type) { |
573 | struct sockaddr_storage sa; |
574 | socklen_t salen = sizeof(sa); |
575 | |
576 | if (fd_to_str_type == FD_TO_PEER_NAME) { |
577 | if (getpeername(fd, (struct sockaddr *)&sa, &salen) == -1) goto error; |
578 | } else { |
579 | if (getsockname(fd, (struct sockaddr *)&sa, &salen) == -1) goto error; |
580 | } |
581 | |
582 | if (sa.ss_family == AF_INET) { |
583 | struct sockaddr_in *s = (struct sockaddr_in *)&sa; |
584 | if (ip) { |
585 | if (inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len) == NULL) |
586 | goto error; |
587 | } |
588 | if (port) *port = ntohs(s->sin_port); |
589 | } else if (sa.ss_family == AF_INET6) { |
590 | struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa; |
591 | if (ip) { |
592 | if (inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len) == NULL) |
593 | goto error; |
594 | } |
595 | if (port) *port = ntohs(s->sin6_port); |
596 | } else if (sa.ss_family == AF_UNIX) { |
597 | if (ip) { |
598 | int res = snprintf(ip, ip_len, "/unixsocket" ); |
599 | if (res < 0 || (unsigned int) res >= ip_len) goto error; |
600 | } |
601 | if (port) *port = 0; |
602 | } else { |
603 | goto error; |
604 | } |
605 | return 0; |
606 | |
607 | error: |
608 | if (ip) { |
609 | if (ip_len >= 2) { |
610 | ip[0] = '?'; |
611 | ip[1] = '\0'; |
612 | } else if (ip_len == 1) { |
613 | ip[0] = '\0'; |
614 | } |
615 | } |
616 | if (port) *port = 0; |
617 | return -1; |
618 | } |
619 | |
620 | /* Format an IP,port pair into something easy to parse. If IP is IPv6 |
621 | * (matches for ":"), the ip is surrounded by []. IP and port are just |
622 | * separated by colons. This the standard to display addresses within Redis. */ |
623 | int anetFormatAddr(char *buf, size_t buf_len, char *ip, int port) { |
624 | return snprintf(buf,buf_len, strchr(ip,':') ? |
625 | "[%s]:%d" : "%s:%d" , ip, port); |
626 | } |
627 | |
628 | /* Like anetFormatAddr() but extract ip and port from the socket's peer/sockname. */ |
629 | int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type) { |
630 | char ip[INET6_ADDRSTRLEN]; |
631 | int port; |
632 | |
633 | anetFdToString(fd,ip,sizeof(ip),&port,fd_to_str_type); |
634 | return anetFormatAddr(buf, buf_len, ip, port); |
635 | } |
636 | |
637 | /* Create a pipe buffer with given flags for read end and write end. |
638 | * Note that it supports the file flags defined by pipe2() and fcntl(F_SETFL), |
639 | * and one of the use cases is O_CLOEXEC|O_NONBLOCK. */ |
640 | int anetPipe(int fds[2], int read_flags, int write_flags) { |
641 | int pipe_flags = 0; |
642 | #if defined(__linux__) || defined(__FreeBSD__) |
643 | /* When possible, try to leverage pipe2() to apply flags that are common to both ends. |
644 | * There is no harm to set O_CLOEXEC to prevent fd leaks. */ |
645 | pipe_flags = O_CLOEXEC | (read_flags & write_flags); |
646 | if (pipe2(fds, pipe_flags)) { |
647 | /* Fail on real failures, and fallback to simple pipe if pipe2 is unsupported. */ |
648 | if (errno != ENOSYS && errno != EINVAL) |
649 | return -1; |
650 | pipe_flags = 0; |
651 | } else { |
652 | /* If the flags on both ends are identical, no need to do anything else. */ |
653 | if ((O_CLOEXEC | read_flags) == (O_CLOEXEC | write_flags)) |
654 | return 0; |
655 | /* Clear the flags which have already been set using pipe2. */ |
656 | read_flags &= ~pipe_flags; |
657 | write_flags &= ~pipe_flags; |
658 | } |
659 | #endif |
660 | |
661 | /* When we reach here with pipe_flags of 0, it means pipe2 failed (or was not attempted), |
662 | * so we try to use pipe. Otherwise, we skip and proceed to set specific flags below. */ |
663 | if (pipe_flags == 0 && pipe(fds)) |
664 | return -1; |
665 | |
666 | /* File descriptor flags. |
667 | * Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. */ |
668 | if (read_flags & O_CLOEXEC) |
669 | if (fcntl(fds[0], F_SETFD, FD_CLOEXEC)) |
670 | goto error; |
671 | if (write_flags & O_CLOEXEC) |
672 | if (fcntl(fds[1], F_SETFD, FD_CLOEXEC)) |
673 | goto error; |
674 | |
675 | /* File status flags after clearing the file descriptor flag O_CLOEXEC. */ |
676 | read_flags &= ~O_CLOEXEC; |
677 | if (read_flags) |
678 | if (fcntl(fds[0], F_SETFL, read_flags)) |
679 | goto error; |
680 | write_flags &= ~O_CLOEXEC; |
681 | if (write_flags) |
682 | if (fcntl(fds[1], F_SETFL, write_flags)) |
683 | goto error; |
684 | |
685 | return 0; |
686 | |
687 | error: |
688 | close(fds[0]); |
689 | close(fds[1]); |
690 | return -1; |
691 | } |
692 | |
693 | int anetSetSockMarkId(char *err, int fd, uint32_t id) { |
694 | #ifdef HAVE_SOCKOPTMARKID |
695 | if (setsockopt(fd, SOL_SOCKET, SOCKOPTMARKID, (void *)&id, sizeof(id)) == -1) { |
696 | anetSetError(err, "setsockopt: %s" , strerror(errno)); |
697 | return ANET_ERR; |
698 | } |
699 | return ANET_OK; |
700 | #else |
701 | UNUSED(fd); |
702 | UNUSED(id); |
703 | anetSetError(err,"anetSetSockMarkid unsupported on this platform" ); |
704 | return ANET_OK; |
705 | #endif |
706 | } |
707 | |