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); }
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; }
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); }
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; }
static void _ds_serv_cache_free(void *x) { if (x != NULL) si_item_release(x); }
/* _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); }
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; }
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; }
/* * 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; }
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; }