From owner-svn-src-head@freebsd.org Tue Nov 22 13:30:09 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1BDF9C4DD2C; Tue, 22 Nov 2016 13:30:09 +0000 (UTC) (envelope-from des@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D2E9211DB; Tue, 22 Nov 2016 13:30:08 +0000 (UTC) (envelope-from des@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAMDU8ik052992; Tue, 22 Nov 2016 13:30:08 GMT (envelope-from des@FreeBSD.org) Received: (from des@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAMDU7fg052989; Tue, 22 Nov 2016 13:30:07 GMT (envelope-from des@FreeBSD.org) Message-Id: <201611221330.uAMDU7fg052989@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: des set sender to des@FreeBSD.org using -f From: =?UTF-8?Q?Dag-Erling_Sm=c3=b8rgrav?= Date: Tue, 22 Nov 2016 13:30:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308996 - head/lib/libfetch X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Nov 2016 13:30:09 -0000 Author: des Date: Tue Nov 22 13:30:07 2016 New Revision: 308996 URL: https://svnweb.freebsd.org/changeset/base/308996 Log: Refactor fetch_connect() and fetch_bind() to improve readability and avoid repeating the same DNS lookups. MFC after: 3 weeks Modified: head/lib/libfetch/common.c head/lib/libfetch/common.h head/lib/libfetch/ftp.c Modified: head/lib/libfetch/common.c ============================================================================== --- head/lib/libfetch/common.c Tue Nov 22 13:24:57 2016 (r308995) +++ head/lib/libfetch/common.c Tue Nov 22 13:30:07 2016 (r308996) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998-2014 Dag-Erling Smørgrav + * Copyright (c) 1998-2016 Dag-Erling Smørgrav * Copyright (c) 2013 Michael Gmelin * All rights reserved. * @@ -241,27 +241,83 @@ fetch_ref(conn_t *conn) /* + * Resolve an address + */ +struct addrinfo * +fetch_resolve(const char *addr, int port, int af) +{ + char hbuf[256], sbuf[8]; + struct addrinfo hints, *res; + const char *sep, *host, *service; + int err, len; + + /* split address if necessary */ + err = EAI_SYSTEM; + if ((sep = strchr(addr, ':')) != NULL) { + len = snprintf(hbuf, sizeof(hbuf), + "%.*s", (int)(sep - addr), addr); + if (len < 0) + return (NULL); + if (len >= (int)sizeof(hbuf)) { + errno = ENAMETOOLONG; + fetch_syserr(); + return (NULL); + } + host = hbuf; + service = sep + 1; + } else if (port != 0) { + if (port < 1 || port > 65535) { + errno = EINVAL; + fetch_syserr(); + return (NULL); + } + if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0) { + fetch_syserr(); + return (NULL); + } + host = addr; + service = sbuf; + } else { + host = addr; + service = NULL; + } + + /* resolve */ + fetch_info("resolving host = %s service = %s af = %d", + host, service, af); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + if ((err = getaddrinfo(host, service, &hints, &res)) != 0) { + netdb_seterr(err); + fetch_info("getaddrinfo() failed: %s", gai_strerror(err)); + return (NULL); + } + fetch_info("getaddrinfo() succeeded %p", res); + return (res); +} + + + +/* * Bind a socket to a specific local address */ int fetch_bind(int sd, int af, const char *addr) { - struct addrinfo hints, *res, *res0; + struct addrinfo *cliai, *ai; int err; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = af; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) + if ((cliai = fetch_resolve(addr, 0, af)) == NULL) return (-1); - for (res = res0; res; res = res->ai_next) - if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) { - freeaddrinfo(res0); - return (0); - } - freeaddrinfo(res0); - return (-1); + for (ai = cliai; ai != NULL; ai = ai->ai_next) + if ((err = bind(sd, ai->ai_addr, ai->ai_addrlen)) == 0) + break; + if (err != 0) + fetch_syserr(); + freeaddrinfo(cliai); + return (err == 0 ? 0 : -1); } @@ -271,59 +327,77 @@ fetch_bind(int sd, int af, const char *a conn_t * fetch_connect(const char *host, int port, int af, int verbose) { - conn_t *conn; - char pbuf[10]; + struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai; const char *bindaddr; - struct addrinfo hints, *res, *res0; - int sd, err; + conn_t *conn = NULL; + int err = 0, sd = -1; DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); + /* resolve server address */ if (verbose) - fetch_info("looking up %s", host); + fetch_info("resolving server address: %s:%d", host, port); + if ((sais = fetch_resolve(host, port, af)) == NULL) + goto fail; + fetch_info("resolved"); - /* look up host name and set up socket address structure */ - snprintf(pbuf, sizeof(pbuf), "%d", port); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = af; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { - netdb_seterr(err); - return (NULL); - } + /* resolve client address */ bindaddr = getenv("FETCH_BIND_ADDRESS"); + if (bindaddr != NULL && *bindaddr != '\0') { + if (verbose) + fetch_info("resolving client address: %s", bindaddr); + if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL) + goto fail; + } - if (verbose) - fetch_info("connecting to %s:%d", host, port); - - /* try to connect */ - for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { - if ((sd = socket(res->ai_family, res->ai_socktype, - res->ai_protocol)) == -1) - continue; - if (bindaddr != NULL && *bindaddr != '\0' && - fetch_bind(sd, res->ai_family, bindaddr) != 0) { - fetch_info("failed to bind to '%s'", bindaddr); - close(sd); - continue; + /* try each server address in turn */ + for (err = 0, sai = sais; sai != NULL; sai = sai->ai_next) { + /* open socket */ + if ((sd = socket(sai->ai_family, SOCK_STREAM, 0)) < 0) + goto syserr; + /* attempt to bind to client address */ + for (err = 0, cai = cais; cai != NULL; cai = cai->ai_next) { + if (cai->ai_family != sai->ai_family) + continue; + if ((err = bind(sd, cai->ai_addr, cai->ai_addrlen)) == 0) + break; + } + if (err != 0) { + if (verbose) + fetch_info("failed to bind to %s", bindaddr); + goto syserr; } - if (connect(sd, res->ai_addr, res->ai_addrlen) == 0 && - fcntl(sd, F_SETFL, O_NONBLOCK) == 0) + /* attempt to connect to server address */ + if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0) break; + /* clean up before next attempt */ close(sd); + sd = -1; } - freeaddrinfo(res0); - if (sd == -1) { - fetch_syserr(); - return (NULL); + if (err != 0) { + if (verbose) + fetch_info("failed to connect to %s:%s", host, port); + goto syserr; } - if ((conn = fetch_reopen(sd)) == NULL) { - fetch_syserr(); - close(sd); - } + if ((conn = fetch_reopen(sd)) == NULL) + goto syserr; + if (cais != NULL) + freeaddrinfo(cais); + if (sais != NULL) + freeaddrinfo(sais); return (conn); +syserr: + fetch_syserr(); + goto fail; +fail: + if (sd >= 0) + close(sd); + if (cais != NULL) + freeaddrinfo(cais); + if (sais != NULL) + freeaddrinfo(sais); + return (NULL); } #ifdef WITH_SSL Modified: head/lib/libfetch/common.h ============================================================================== --- head/lib/libfetch/common.h Tue Nov 22 13:24:57 2016 (r308995) +++ head/lib/libfetch/common.h Tue Nov 22 13:30:07 2016 (r308996) @@ -76,6 +76,7 @@ void fetch_syserr(void); void fetch_info(const char *, ...); int fetch_default_port(const char *); int fetch_default_proxy_port(const char *); +struct addrinfo *fetch_resolve(const char *, int, int); int fetch_bind(int, int, const char *); conn_t *fetch_connect(const char *, int, int, int); conn_t *fetch_reopen(int); Modified: head/lib/libfetch/ftp.c ============================================================================== --- head/lib/libfetch/ftp.c Tue Nov 22 13:24:57 2016 (r308995) +++ head/lib/libfetch/ftp.c Tue Nov 22 13:30:07 2016 (r308996) @@ -768,8 +768,8 @@ ftp_transfer(conn_t *conn, const char *o fetch_info("opening data connection"); bindaddr = getenv("FETCH_BIND_ADDRESS"); if (bindaddr != NULL && *bindaddr != '\0' && - fetch_bind(sd, sa.ss_family, bindaddr) != 0) - goto sysouch; + (e = fetch_bind(sd, sa.ss_family, bindaddr)) != 0) + goto ouch; if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1) goto sysouch;