/* Initiate a connection to <address> by resolving the * hostname and returning a struct with necessary * connection info. */ static struct vss_addr * init_connection(const char *address) { struct vss_addr **ta; struct vss_addr *tap; char *addr, *port; int i, n; if (VSS_parse(address, &addr, &port) != 0) { thread_log(0, 0, "Invalid address"); exit(2); } n = VSS_resolve(addr, port, &ta); free(addr); free(port); if (n == 0) { thread_log(0, 0, "Could not connect to server"); exit(2); } for (i = 1; i < n; ++i) { free(ta[i]); ta[i] = NULL; } tap = ta[0]; free(ta); return (tap); }
/* * For a given host and port, return a list of struct vss_addr, which * contains all the information necessary to open and bind a socket. One * vss_addr is returned for each distinct address returned by * getaddrinfo(). * * The value pointed to by the tap parameter receives a pointer to an * array of pointers to struct vss_addr. The caller is responsible for * freeing each individual struct vss_addr as well as the array. * * The return value is the number of addresses resoved, or zero. * * If the addr argument contains a port specification, that takes * precedence over the port argument. * * XXX: We need a function to free the allocated addresses. */ int VSS_resolve(const char *addr, const char *port, struct vss_addr ***vap) { struct addrinfo hints, *res0, *res; struct vss_addr **va; int i, ret; long int ptst; char *adp, *hop; *vap = NULL; memset(&hints, 0, sizeof hints); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; ret = VSS_parse(addr, &hop, &adp); if (ret) return (0); if (adp == NULL) ret = getaddrinfo(addr, port, &hints, &res0); else { ptst = strtol(adp,NULL,10); if (ptst < 0 || ptst > 65535) return(0); ret = getaddrinfo(hop, adp, &hints, &res0); } free(hop); free(adp); if (ret != 0) return (0); XXXAN(res0); for (res = res0, i = 0; res != NULL; res = res->ai_next, ++i) /* nothing */ ; if (i == 0) { freeaddrinfo(res0); return (0); } va = calloc(i, sizeof *va); XXXAN(va); *vap = va; for (res = res0, i = 0; res != NULL; res = res->ai_next, ++i) { va[i] = calloc(1, sizeof(**va)); XXXAN(va[i]); va[i]->va_family = res->ai_family; va[i]->va_socktype = res->ai_socktype; va[i]->va_protocol = res->ai_protocol; va[i]->va_addrlen = res->ai_addrlen; xxxassert(va[i]->va_addrlen <= sizeof va[i]->va_addr); memcpy(&va[i]->va_addr, res->ai_addr, va[i]->va_addrlen); } freeaddrinfo(res0); return (i); }
static void Emit_Sockaddr(struct vcc *tl, const struct token *t_host, const char *port) { struct foo_proto protos[3], *pp; struct addrinfo *res, *res0, *res1, hint; int error, retval, x; char hbuf[NI_MAXHOST]; char *hop, *pop; AN(t_host->dec); memset(protos, 0, sizeof protos); protos[0].name = "ipv4"; protos[0].family = PF_INET; protos[1].name = "ipv6"; protos[1].family = PF_INET6; retval = 0; memset(&hint, 0, sizeof hint); hint.ai_family = PF_UNSPEC; hint.ai_socktype = SOCK_STREAM; if (VSS_parse(t_host->dec, &hop, &pop)) { VSB_printf(tl->sb, "Backend host '%.*s': wrong syntax (unbalanced [...] ?)\n", PF(t_host) ); vcc_ErrWhere(tl, t_host); return; } error = getaddrinfo( hop != NULL ? hop : t_host->dec, pop != NULL ? pop : port, &hint, &res0); free(hop); free(pop); if (error) { VSB_printf(tl->sb, "Backend host '%.*s'" " could not be resolved to an IP address:\n", PF(t_host)); VSB_printf(tl->sb, "\t%s\n" "(Sorry if that error message is gibberish.)\n", gai_strerror(error)); vcc_ErrWhere(tl, t_host); return; } for (res = res0; res; res = res->ai_next) { for (pp = protos; pp->name != NULL; pp++) if (res->ai_family == pp->family) break; if (pp->name == NULL) { /* Unknown proto, ignore */ continue; } if (pp->l == res->ai_addrlen && !memcmp(&pp->sa, res->ai_addr, pp->l)) { /* * Same address we already emitted. * This can happen using /etc/hosts */ continue; } if (pp->l > 0) { VSB_printf(tl->sb, "Backend host %.*s: resolves to " "multiple %s addresses.\n" "Only one address is allowed.\n" "Please specify which exact address " "you want to use, we found these:\n", PF(t_host), pp->name); for (res1 = res0; res1 != NULL; res1 = res1->ai_next) { error = getnameinfo(res1->ai_addr, res1->ai_addrlen, hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST); AZ(error); VSB_printf(tl->sb, "\t%s\n", hbuf); } freeaddrinfo(res0); vcc_ErrWhere(tl, t_host); return; } pp->l = res->ai_addrlen; memcpy(&pp->sa, res->ai_addr, pp->l); x = emit_sockaddr(tl, res->ai_addr, res->ai_addrlen); Fb(tl, 0, "\t.%s_sockaddr = sockaddr_%u,\n", pp->name, x); error = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST); AZ(error); Fb(tl, 0, "\t.%s_addr = \"%s\",\n", pp->name, hbuf); retval++; } if (res0 != NULL) { error = getnameinfo(res0->ai_addr, res0->ai_addrlen, NULL, 0, hbuf, sizeof hbuf, NI_NUMERICSERV); AZ(error); Fb(tl, 0, "\t.port = \"%s\",\n", hbuf); } freeaddrinfo(res0); if (retval == 0) { VSB_printf(tl->sb, "Backend host '%.*s': resolves to " "neither IPv4 nor IPv6 addresses.\n", PF(t_host) ); vcc_ErrWhere(tl, t_host); } }