X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fnet%2Fnet.c;h=e84380fff96f27a885d05618a46b6d1d2d46cc2c;hb=d4af94ec86618e89b449a27590a7b4f8e4365943;hp=8bcaa937c8955e249173abdff234d9e19ac4a6b6;hpb=708b846815c758645cf19f905513c67f7a024491;p=ccan diff --git a/ccan/net/net.c b/ccan/net/net.c index 8bcaa937..e84380ff 100644 --- a/ccan/net/net.c +++ b/ccan/net/net.c @@ -1,3 +1,4 @@ +/* Licensed under BSD-MIT - see LICENSE file for details */ #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include struct addrinfo *net_client_lookup(const char *hostname, const char *service, @@ -148,3 +150,92 @@ out: errno = saved_errno; return sockfd; } + +struct addrinfo *net_server_lookup(const char *service, + int family, + int socktype) +{ + struct addrinfo *res, hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = 0; + + if (getaddrinfo(NULL, service, &hints, &res) != 0) + return NULL; + + return res; +} + +static bool should_listen(const struct addrinfo *addrinfo) +{ +#ifdef SOCK_SEQPACKET + if (addrinfo->ai_socktype == SOCK_SEQPACKET) + return true; +#endif + return (addrinfo->ai_socktype == SOCK_STREAM); +} + +static int make_listen_fd(const struct addrinfo *addrinfo) +{ + int saved_errno, fd, on = 1; + + fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (fd < 0) + return -1; + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) + goto fail; + + if (should_listen(addrinfo) && listen(fd, 5) != 0) + goto fail; + return fd; + +fail: + saved_errno = errno; + close(fd); + errno = saved_errno; + return -1; +} + +int net_bind(const struct addrinfo *addrinfo, int fds[2]) +{ + const struct addrinfo *ipv6 = NULL; + const struct addrinfo *ipv4 = NULL; + unsigned int num; + + if (addrinfo->ai_family == AF_INET) + ipv4 = addrinfo; + else if (addrinfo->ai_family == AF_INET6) + ipv6 = addrinfo; + + if (addrinfo->ai_next) { + if (addrinfo->ai_next->ai_family == AF_INET) + ipv4 = addrinfo->ai_next; + else if (addrinfo->ai_next->ai_family == AF_INET6) + ipv6 = addrinfo->ai_next; + } + + num = 0; + /* Take IPv6 first, since it might bind to IPv4 port too. */ + if (ipv6) { + if ((fds[num] = make_listen_fd(ipv6)) >= 0) + num++; + else + ipv6 = NULL; + } + if (ipv4) { + if ((fds[num] = make_listen_fd(ipv4)) >= 0) + num++; + else + ipv4 = NULL; + } + if (num == 0) + return -1; + + return num; +}