static void
si_async_workunit_release(si_async_workunit_t *r)
{
	if (r == NULL) return;

	if (OSAtomicDecrement32Barrier(&(r->refcount)) != 0) return;

#ifdef CALL_TRACE
	fprintf(stderr, "** %s freeing worklist item %p\n", __func__, r);
#endif

	si_async_worklist_remove_unit(r);

	if (r->resitem != NULL) si_item_release(r->resitem);
	if (r->reslist != NULL) si_list_release(r->reslist);

	if (r->str1 != NULL) free(r->str1);
	if (r->str2 != NULL) free(r->str2);
	if (r->str3 != NULL) free(r->str3);

	/* release send-once right if it has not been used */
	if (r->send != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), r->send);

	/* release receive right */
	mach_port_mod_refs(mach_task_self(), r->port, MACH_PORT_RIGHT_RECEIVE, -1);

	free(r);
}
Пример #2
0
void
LI_set_thread_item(uint32_t key, si_item_t *item)
{
	li_thread_data_t *tdata;

	tdata = LI_get_thread_info(key);
	if (tdata == NULL) return;

	si_item_release(tdata->thread_item);
	tdata->thread_item = item;
}
Пример #3
0
static void
_LI_thread_info_free(void *x)
{
	li_thread_data_t *tdata;

	if (x == NULL) return;

	tdata = (li_thread_data_t *)x;
	si_item_release(tdata->thread_item);
	si_list_release(tdata->thread_list);

	free(tdata);
}
Пример #4
0
int
_gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port)
{
	si_item_t *item;
	struct servent *s;
	const char *protoname = NULL;

	if (_gai_numericserv(serv, port)) return 0;

	if (proto == IPPROTO_UDP) protoname = "udp";
	if (proto == IPPROTO_TCP) protoname = "tcp";

	item = si_service_byname(si_search(), serv, protoname);
	if (item == NULL) return -1;

	s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
	if (port) *port = ntohs(s->s_port);
	si_item_release(item);

	return 0;
}
Пример #5
0
static void
_ds_serv_cache_free(void *x)
{
	if (x != NULL) si_item_release(x);
}
Пример #6
0
/* _gai_simple
 * Simple lookup via gethostbyname2(3) mechanism.
 */
si_list_t *
_gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
{
	si_item_t *h4_item = NULL, *h6_item = NULL;
	struct hostent *h4 = NULL, *h6 = NULL;
	si_list_t *out = NULL;
	uint16_t port = 0;

	if ((flags & AI_NUMERICSERV) != 0 && servptr != NULL)
	{
		port = *(uint16_t*)servptr;
	}
	else if (servptr != NULL)
	{
		if (_gai_serv_to_port(servptr, proto, &port) != 0)
		{
			if (err) *err = SI_STATUS_EAI_NONAME;
			return NULL;
		}
	}

	if ((flags & AI_NUMERICHOST) != 0)
	{
		if (family == AF_INET)
		{
			h4_item = si_host_byaddr(si, nodeptr, AF_INET, interface, NULL);
		}
		else if (family == AF_INET6)
		{
			h6_item = si_host_byaddr(si, nodeptr, AF_INET6, interface, NULL);
		}
	}
	else
	{
		if ((family == AF_INET) || (family == AF_UNSPEC))
		{
			h4_item = si_host_byname(si, nodeptr, AF_INET, interface, NULL);
		}

		if ((family == AF_INET6) || (family == AF_UNSPEC))
		{
			h6_item = si_host_byname(si, nodeptr, AF_INET6, interface, NULL);
		}
	}

	if (h4_item != NULL)
	{
		h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t));
	}

	if (h6_item != NULL)
	{
		h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t));
	}

	out = si_addrinfo_list_from_hostent(si, flags, socktype, proto, port, 0, h4, h6);
	si_item_release(h4_item);
	si_item_release(h6_item);

	return _gai_sort_list(out, flags);
}
Пример #7
0
static si_list_t *
_gai_sort_list(si_list_t *in, uint32_t flags)
{
	si_list_t *out;
	int filter_mapped;
	uint32_t i;
	uint32_t v4mapped_count = 0;
	uint32_t v6_count = 0;
	si_addrinfo_t *a;

	if (in == NULL) return NULL;

	for (i = 0; i < in->count; i++)
	{
		a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
		if (a->ai_family == AF_INET6)
		{
			struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
			if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr))) v4mapped_count++;
			else v6_count++;
		}
	}

	filter_mapped = 1;
	if ((flags & AI_V4MAPPED) && ((v6_count == 0) || (flags & AI_ALL))) filter_mapped = 0;

	out = in;

	if ((filter_mapped == 1) && (v4mapped_count > 0))
	{
		i = in->count - v4mapped_count;
		if (i == 0) return NULL;

		out = (si_list_t *)calloc(1, sizeof(si_list_t));
		if (out == NULL) return in;

		out->count = i;
		out->refcount = in->refcount;

		out->entry = (si_item_t **)calloc(out->count, sizeof(si_item_t *));
		if (out->entry == NULL)
		{
			free(out);
			return in;
		}

		out->curr = 0;

		for (i = 0; i < in->count; i++)
		{
			a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
			if (a->ai_family == AF_INET6)
			{
				struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
				if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr)))
				{
					si_item_release(in->entry[i]);
					continue;
				}
			}

			out->entry[out->curr++] = in->entry[i];
		}

		out->curr = 0;

		free(in->entry);
		free(in);
	}

	qsort(&out->entry[0], out->count, sizeof(si_item_t *), _gai_addr_sort);
	return out;
}
Пример #8
0
si_list_t *
si_addrinfo_list(si_mod_t *si, uint32_t flags, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6)
{
	int do_map = 0;
	si_item_t *item = NULL;
	si_list_t *out4 = NULL, *out6 = NULL;

	if ((flags & AI_V4MAPPED) && ((flags & AI_ALL) || (a6 == NULL))) do_map = 1;

	if (a6 != NULL)
	{
		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
		{
			item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6);
			out6 = si_list_add(out6, item);
			si_item_release(item);
		}

		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
		{
			item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6);
			out6 = si_list_add(out6, item);
			si_item_release(item);
		}

		if (proto == IPPROTO_ICMPV6)
		{
			item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6);
			out6 = si_list_add(out6, item);
			si_item_release(item);
		}
	}

	if (a4 != NULL)
	{
		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
		{
			if (do_map == 0)
			{
				item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
				out4 = si_list_add(out4, item);
			}
			else
			{
				item = si_addrinfo_v4_mapped(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
				out6 = si_list_add(out6, item);
			}

			si_item_release(item);
		}

		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
		{
			if (do_map == 0)
			{
				item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
				out4 = si_list_add(out4, item);
			}
			else
			{
				item = si_addrinfo_v4_mapped(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
				out6 = si_list_add(out6, item);
			}

			si_item_release(item);
		}

		if (proto == IPPROTO_ICMP)
		{
			if (do_map == 0)
			{
				item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
				out4 = si_list_add(out4, item);
			}
			else
			{
				item = si_addrinfo_v4_mapped(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
				out6 = si_list_add(out6, item);
			}

			si_item_release(item);
		}
	}

	out6 = si_list_concat(out6, out4);
	si_list_release(out4);

	return out6;
}
Пример #9
0
/*
 * getnameinfo
 *
 * We handle some "trival" cases locally.  If the caller passes
 * NI_NUMERICHOST (only), then this call turns into a getservbyport
 * to get the service name + inet_pton() to create a host string.
 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
 * number, complete the getnameinfo, and use printf() to create a service
 * string.  If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
 * we inet_ntop() and printf() and return the results.
 */
si_item_t *
si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
{
	si_item_t *out = NULL;
	const struct sockaddr *lookup_sa;
	struct sockaddr_in s4;
	struct in_addr a4;
	struct in6_addr a6;
	const uint32_t unused = 0;
	void *addr = NULL;
	char *host = NULL;
	char *serv = NULL;
	uint32_t ifnum = 0;
	uint16_t port = 0;

	int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
	int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);

	/* check input */
	if ((si == NULL) || (sa == NULL))
	{
		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
		return NULL;
	}

	if (err != NULL) *err = SI_STATUS_NO_ERROR;

	lookup_sa = sa;

	if (sa->sa_family == AF_INET)
	{
		struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
		memcpy(&a4, &s4->sin_addr, sizeof(a4));
		port = s4->sin_port;
		addr = &a4;
	}
	else if (sa->sa_family == AF_INET6)
	{
		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
		memcpy(&a6, &s6->sin6_addr, sizeof(a6));
		port = s6->sin6_port;

		/* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
		if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))
		{
			ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
			if (ifnum == 0)
			{
				ifnum = s6->sin6_scope_id;
				a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
			}

			if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0))
			{
				if (err != NULL) *err = SI_STATUS_EAI_FAIL;
				return NULL;
			}
		}

		/* v4 mapped and compat addresses are converted to plain v4 */
		if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
		{
			memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
			addr = &a4;
			memset(&s4, 0, sizeof(s4));
			s4.sin_len = sizeof(s4);
			s4.sin_family = AF_INET;
			s4.sin_port = port;
			memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
			lookup_sa = (const struct sockaddr *)&s4;
		}
		else
		{
			addr = &a6;
		}
	}
	else
	{
		if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
		return NULL;
	}

	if (do_host_lookup == 1)
	{
		si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL);
		if (item != NULL)
		{
			struct hostent *h;
			h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
			host = strdup(h->h_name);
			si_item_release(item);
			if (host == NULL)
			{
				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
				return NULL;
			}
		}
	}

	if ((do_serv_lookup == 1) && (port != 0))
	{
		si_item_t *item = si_service_byport(si, port, NULL);
		if (item != NULL)
		{
			struct servent *s;
			s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
			serv = strdup(s->s_name);
			si_item_release(item);
			if (serv == NULL)
			{
				free(host);
				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
				return NULL;
			}
		}
	}

	/*
	 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
	 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
	 */
	if ((host == NULL) && ((flags & NI_NAMEREQD) == 0))
	{
		char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
		tmp[0] = '\0';
		if (sa->sa_family == AF_INET)
		{
			char buf[INET_ADDRSTRLEN];
			if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
			{
				host = strdup(buf);
			}
		}
		else if (sa->sa_family == AF_INET6)
		{
			char buf[INET6_ADDRSTRLEN];

			/* zero the embedded scope ID */
			if (ifnum != 0)
			{
				a6.__u6_addr.__u6_addr16[1] = 0;
			}

			if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
			{
				if (ifnum != 0)
				{
					char ifname[IF_NAMESIZE];
					if (if_indextoname(ifnum, ifname) != NULL)
					{
						asprintf(&host, "%s%%%s", buf, ifname);
					}
					else
					{
						/* ENXIO */
						if (err != NULL) *err = SI_STATUS_EAI_FAIL;
						return NULL;
					}
				}
				else
				{
					host = strdup(buf);
				}
			}
		}
	}

	/* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
	if (serv == NULL)
	{
		asprintf(&serv, "%hu", ntohs(port));
	}

	if ((host == NULL) || (serv == NULL))
	{
		if (err != NULL)
		{
			if ((flags & NI_NAMEREQD) != 0)
			{
				*err = SI_STATUS_EAI_NONAME;
			}
			else
			{
				*err = SI_STATUS_EAI_MEMORY;
			}
		}
	}
	else
	{
		out = (si_item_t *)LI_ils_create("L4444ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
	}

	free(host);
	free(serv);
	return out;
}
Пример #10
0
si_item_t *
si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err)
{
	int i, status, want;
	uint32_t if4, if6;
	struct in_addr addr4;
	struct in6_addr addr6;
	si_item_t *item4, *item6;
	build_hostent_t *out;
	struct hostent *h;
	uint32_t unused;

	memset(&addr4, 0, sizeof(struct in_addr));
	memset(&addr6, 0, sizeof(struct in6_addr));

	if (err != NULL) *err = 0;

	if (family == AF_INET)
	{
		status = inet_aton(name, &addr4);
		if (status == 1)
		{
			/* create a host entry */
			item4 = make_hostent(si, name, addr4);
			if (item4 == NULL)
			{
				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
				return NULL;
			}

			return item4;
		}
	}
	else if (family == AF_INET6)
	{
		status = inet_pton(family, name, &addr6);
		if (status == 1)
		{
			/* create a host entry */
			item6 = make_hostent6(si, name, addr6);
			if (item6 == NULL)
			{
				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
				return NULL;
			}

			return item6;
		}

		status = inet_aton(name, &addr4);
		if (status == 1)
		{
			if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)))
			{
				if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
				return NULL;
			}

			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
			memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);

			/* create a host entry */
			item6 = make_hostent6(si, name, addr6);
			if (item6 == NULL)
			{
				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
				return NULL;
			}

			return item6;
		}
	}
	else
	{
		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
		return NULL;
	}

	/*
	 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
	 */

	if4 = 0;
	if6 = 0;

	if (flags & AI_ADDRCONFIG)
	{
		if (si_inet_config(&if4, &if6) < 0)
		{
			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
			return NULL;
		}

		/* Bail out if there are no interfaces */
		if ((if4 == 0) && (if6 == 0))
		{
			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
			return NULL;
		}
	}

	/*
	 * Figure out what we want.
	 * If user asked for AF_INET, we only want V4 addresses.
	 */
	want = WANT_A4_ONLY;

	if (family == AF_INET)
	{
		if ((flags & AI_ADDRCONFIG) && (if4 == 0))
		{
			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
			return NULL;
		}
	}
	else if (family == AF_INET6)
	{
		/* family == AF_INET6 */
		want = WANT_A6_ONLY;

		if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
		{
			if (flags & AI_ALL)
			{
				want = WANT_A6_PLUS_MAPPED_A4;
			}
			else
			{
				want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
			}
		}
		else
		{
			if ((flags & AI_ADDRCONFIG) && (if6 == 0)) 
			{
				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
				return NULL;
			}
		}
	}
	else
	{
		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
		return NULL;
	}

	item6 = NULL;
	item4 = NULL;

	/* fetch IPv6 data if required */
	if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4))
	{
		item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err);
	}

	/* fetch IPv4 data if required */
	if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL)))
	{
		item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err);
	}

	if (want == WANT_A4_ONLY)
	{
		si_item_release(item6);
		if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
		return item4;
	}

	if (want == WANT_A6_ONLY)
	{
		si_item_release(item4);
		if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
		return item6;
	}

	if ((item6 == NULL) && (item4 == NULL))
	{
		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
		return NULL;
	}

	/* output item will have IPv6 + mapped IPv4 addresses */

	out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t));
	if (out == NULL)
	{
		si_item_release(item4);
		si_item_release(item6);
		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
		return NULL;
	}

	if (item4 != NULL)
	{
		h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t));

		out->host.h_name = lower_case(h->h_name);

		if (h->h_aliases != NULL)
		{
			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
		}

		for (i = 0; h->h_addr_list[i] != 0; i++)
		{
			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
			memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN);
			append_addr((const char *)&addr6, IPV6_ADDR_LEN, out);
		}
	}

	if (item6 != NULL)
	{
		h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t));

		if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name);

		if (h->h_aliases != NULL)
		{
			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
		}

		for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out);
	}

	si_item_release(item4);
	si_item_release(item6);

	unused = 0;

	item6 = (si_item_t *)LI_ils_create("L4444s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list);

	free_build_hostent(out);

	return item6;
}