/* 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);
}
예제 #2
0
/*
 * 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);
}
예제 #3
0
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);
	}
}