From 06e47cd5c6d93afa59eadfa6e2ee89b7415180e0 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Fri, 6 Sep 2013 23:17:42 +0000 Subject: [PATCH] net: Split makesock(), part 1: Introduce lookup_address(). The lookup part is relatively independent and might be useful on its own, so create lookup_address(). --- net.c | 107 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/net.c b/net.c index 70d3ec0f..ccb9632d 100644 --- a/net.c +++ b/net.c @@ -343,72 +343,91 @@ static void flowopt_cleanup(struct flowopts *fo) free(fo); } -/** - * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket. +/* + * Resolve an IPv4/IPv6 address. * * \param l4type The layer-4 type (\p IPPROTO_xxx). - * \param passive Whether this is a passive (1) or active (0) socket. + * \param passive Whether \p AI_PASSIVE should be included as hint. * \param host Remote or local hostname or IPv/6 address string. - * \param port_number Decimal port number. - * \param fo Socket options to be set before making the connection. + * \param port_number Used to set the port in each returned address structure. + * \param result addrinfo structures are returned here. * - * This creates a ready-made IPv4/v6 socket structure after looking up the - * necessary parameters. The interpretation of \a host depends on the value of - * \a passive: - * - on a passive socket host is interpreted as an interface IPv4/6 address - * (can be left NULL); - * - on an active socket, \a host is the peer DNS name or IPv4/6 address - * to connect to; - * - \a port_number is in either case the numeric port number (not service - * string). + * The interpretation of \a host depends on the value of \a passive. On a + * passive socket host is interpreted as an interface IPv4/6 address (can be + * left NULL). On an active socket, \a host is the peer DNS name or IPv4/6 + * address to connect to. * - * Furthermore, bind(2) is called on passive sockets, and connect(2) on active - * sockets. The algorithm tries all possible address combinations until it - * succeeds. If \a fo is supplied, options are set and cleanup is performed. + * \return Standard. * - * \return This function returns 1 on success and \a -E_ADDRESS_LOOKUP when no - * matching connection could be set up (with details in the error log). - * - * \sa ipv6(7), getaddrinfo(3), bind(2), connect(2). + * \sa getaddrinfo(3). */ -int makesock(unsigned l4type, bool passive, - const char *host, uint16_t port_number, - struct flowopts *fo) +static int lookup_address(unsigned l4type, bool passive, const char *host, + int port_number, struct addrinfo **result) { - struct addrinfo *local = NULL, *src = NULL, *remote = NULL, - *dst = NULL, hints; - int rc, on = 1, sockfd = -1, - socktype = sock_type(l4type); + int ret; char port[6]; /* port number has at most 5 digits */ + struct addrinfo *addr = NULL, hints; - sprintf(port, "%u", port_number); + *result = NULL; + sprintf(port, "%u", port_number & 0xffff); /* Set up address hint structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; - hints.ai_socktype = socktype; - /* + hints.ai_socktype = sock_type(l4type); + /* * getaddrinfo does not support SOCK_DCCP, so for the sake of lookup * (and only then) pretend to be UDP. */ if (l4type == IPPROTO_DCCP) hints.ai_socktype = SOCK_DGRAM; - /* only use addresses available on the host */ hints.ai_flags = AI_ADDRCONFIG; - if (passive && host == NULL) hints.ai_flags |= AI_PASSIVE; - /* Obtain local/remote address information */ - if ((rc = getaddrinfo(host, port, &hints, passive ? &local : &remote))) { - PARA_ERROR_LOG("can not resolve %s address %s#%s: %s.\n", - layer4_name(l4type), - host? host : (passive? "[loopback]" : "[localhost]"), - port, gai_strerror(rc)); - rc = -E_ADDRESS_LOOKUP; - goto out; + ret = getaddrinfo(host, port, &hints, &addr); + if (ret != 0) { + PARA_ERROR_LOG("can not resolve %s address %s#%s: %s\n", + layer4_name(l4type), + host? host : (passive? "[loopback]" : "[localhost]"), + port, gai_strerror(ret)); + return -E_ADDRESS_LOOKUP; } + *result = addr; + return 1; +} +/** + * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket. + * + * \param l4type The layer-4 type (\p IPPROTO_xxx). + * \param passive Whether this is a passive or active socket. + * \param host Passed to \ref \a lookup_address(). + * \param port_number Passed to \ref \a lookup_address(). + * \param fo Socket options to be set before making the connection. + * + * This creates a ready-made IPv4/v6 socket structure after looking up the + * necessary parameters. + * + * bind(2) is called on passive sockets, and connect(2) on active sockets. The + * algorithm tries all possible address combinations until it succeeds. If \a + * fo is supplied, options are set and cleanup is performed. + * + * \return Standard. + * + * \sa \ref lookup_address(), ipv6(7), getaddrinfo(3), bind(2), connect(2). + */ +int makesock(unsigned l4type, bool passive, + const char *host, uint16_t port_number, + struct flowopts *fo) +{ + struct addrinfo *local = NULL, *src = NULL, *remote = NULL, *dst = NULL; + int rc, on = 1, sockfd = -1; + + rc = lookup_address(l4type, passive, host, port_number, passive? + &local : &remote); + if (rc < 0) + goto out; /* Iterate over all src/dst combination, exhausting dst first */ for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) { if (src && dst && src->ai_family == AF_INET @@ -416,7 +435,7 @@ int makesock(unsigned l4type, bool passive, goto get_next_dst; /* v4 -> v6 is not possible */ sockfd = socket(src ? src->ai_family : dst->ai_family, - socktype, l4type); + sock_type(l4type), l4type); if (sockfd < 0) goto get_next_dst; @@ -465,9 +484,9 @@ out: if (src == NULL && dst == NULL) { if (rc >= 0) rc = -E_MAKESOCK; - PARA_ERROR_LOG("can not create %s socket %s#%s.\n", + PARA_ERROR_LOG("can not create %s socket %s#%d.\n", layer4_name(l4type), host? host : (passive? - "[loopback]" : "[localhost]"), port); + "[loopback]" : "[localhost]"), port_number); return rc; } return sockfd; -- 2.39.5