Open one or more sockets for incoming data using the specified type, * port, and address. * * The getaddrinfo() call may return several address results, e.g. for * the machine's IPv4 and IPv6 name. * * We return an array of file-descriptors to the sockets, with a trailing * -1 value to indicate the end of the list. * * bind_addr: local address to bind, or NULL to allow it to default. */
| 400 | * |
| 401 | * bind_addr: local address to bind, or NULL to allow it to default. */ |
| 402 | static int *open_socket_in(int type, int port, const char *bind_addr, |
| 403 | int af_hint) |
| 404 | { |
| 405 | int one = 1; |
| 406 | int s, *socks, maxs, i, ecnt; |
| 407 | struct addrinfo hints, *all_ai, *resp; |
| 408 | char portbuf[10], **errmsgs; |
| 409 | int error; |
| 410 | |
| 411 | memset(&hints, 0, sizeof hints); |
| 412 | hints.ai_family = af_hint; |
| 413 | hints.ai_socktype = type; |
| 414 | hints.ai_flags = AI_PASSIVE; |
| 415 | snprintf(portbuf, sizeof portbuf, "%d", port); |
| 416 | error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai); |
| 417 | if (error) { |
| 418 | rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n", |
| 419 | bind_addr, gai_strerror(error)); |
| 420 | return NULL; |
| 421 | } |
| 422 | |
| 423 | /* Count max number of sockets we might open. */ |
| 424 | for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {} |
| 425 | |
| 426 | socks = new_array(int, maxs + 1); |
| 427 | errmsgs = new_array(char *, maxs); |
| 428 | |
| 429 | /* We may not be able to create the socket, if for example the |
| 430 | * machine knows about IPv6 in the C library, but not in the |
| 431 | * kernel. */ |
| 432 | for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) { |
| 433 | s = socket(resp->ai_family, resp->ai_socktype, |
| 434 | resp->ai_protocol); |
| 435 | |
| 436 | if (s == -1) { |
| 437 | int r = asprintf(&errmsgs[ecnt++], |
| 438 | "socket(%d,%d,%d) failed: %s\n", |
| 439 | (int)resp->ai_family, (int)resp->ai_socktype, |
| 440 | (int)resp->ai_protocol, strerror(errno)); |
| 441 | if (r < 0) |
| 442 | out_of_memory("open_socket_in"); |
| 443 | /* See if there's another address that will work... */ |
| 444 | continue; |
| 445 | } |
| 446 | |
| 447 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
| 448 | (char *)&one, sizeof one); |
| 449 | if (sockopts) |
| 450 | set_socket_options(s, sockopts); |
| 451 | else |
| 452 | set_socket_options(s, lp_socket_options()); |
| 453 | |
| 454 | #ifdef IPV6_V6ONLY |
| 455 | if (resp->ai_family == AF_INET6) { |
| 456 | if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof one) < 0 |
| 457 | && default_af_hint != AF_INET6) { |
| 458 | close(s); |
| 459 | continue; |
no test coverage detected