|
Message-ID: <20140530044105.GU507@brightrain.aerifal.cx> Date: Fri, 30 May 2014 00:41:06 -0400 From: Rich Felker <dalias@...c.org> To: musl@...ts.openwall.com Subject: Resolver overhaul started I've started working on the resolver overhaul with a design based on what I described in the thread "Resolver overhaul concepts". The code that's written so far is the outer "getaddrinfo" layer, which uses new internal interfaces for name and service resolving and transforms the output into the linked list format (which, as before, is just an array with each member pointing to the next) covering the direct product of the address results and the service results. This consolidates all of the "struct addrinfo" production in one place, rather than having it duplicated/unrolled all over the place in different cases for passive/localhost, numeric addresses, hosts file, and dns, and makes it so requests that accept either tcp or udp results work correctly. The internal interfaces, which are not yet implemented (well, __lookup_name partially is, but it's missing the interesting parts) are responsible for taking a string and other parameters and filling a caller-provided, fixed-size list of results. Applying filters based on the requested protocol/address-family/flags/etc. is their responsibility, as will be (if/when we add it) sorting the results per RFC 3484. These results are intended to be easily usable by legacy functions like gethostbyname without going through the getaddrinfo API, so that the legacy functions can be implemented without malloc/free (in practice I'll still make them use malloc, to avoid bss bloat in libc.so, but they won't need free, so __simple_malloc can be used when static linking). Various things may still need minor tweaking; for example, the format used for returning addresses may need to change somewhat to accommodate ipv6 scope ids (which are not supported at all in the old code, but should be). But the overall factoring and code flow seem to be how I want them. See below for the current draft. Comments welcome. Rich struct address { int family; uint8_t addr[16]; }; struct service { uint16_t port; char protocol; }; int __lookup_serv(struct service buf[static 2], const char *name, int proto); int __lookup_name(union address *buf[static 32], char canon[static 256], const char *name, int family, int flags); int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) { struct service ports[2]; struct address addrs[32]; char canon[256], *outcanon; int nservs, naddrs, nais, canon_len, i, j, k; int family = AF_UNSPEC, flags = 0, proto = 0; struct aibuf { struct addrinfo ai; union sa { struct sockaddr_in sin; struct sockaddr_in6 sin6; } sa; } *out; if (hint) { family = hint->ai_family; flags = hint->ai_flags; proto = hint->ai_protocol; const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; if ((flags & mask) != flags) return EAI_BADFLAGS; switch (family) { case AF_INET: case AF_INET6: case AF_UNSPEC: break; default: return EAI_FAMILY; } switch (hint->ai_socktype) { case SOCK_STREAM: switch (proto) { case 0: proto = IPPROTO_TCP; case IPPROTO_TCP: break; default: return EAI_SERVICE; } break; case SOCK_DGRAM: switch (proto) { case 0: proto = IPPROTO_UDP; case IPPROTO_UDP: break; default: return EAI_SERVICE; } case 0: break; default: return EAI_SOCKTYPE; } } nservs = __lookup_serv(ports, serv, proto, flags); if (nservs < 0) return nservs; naddrs = __lookup_name(addrs, canon, host, family, flags); if (nadds < 0) return naddrs; nais = nservs * naddrs; canon_len = strlen(canon); out = calloc(1, nais * sizeof(*out) + canon_len + 1); if (!out) return EAI_MEMORY; if (canon_len) { outcanon = (void *)out[nais]; memcpy(outcanon, canon, canon_len+1); } else { outcanon = 0; } for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) { out[k].ai = (struct addrinfo){ .ai_family = addrs[i].family, .ai_socktype = ports[j].proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM, .ai_protocol = ports[j].proto, .ai_addrlen = addrs[i].family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(sturct sockaddr_in6), .ai_addr = (void *)&out[k].sa, .ai_canonname = outcanon, .ai_next = &out[k+1].ai }; switch (addrs[i].family) { case AF_INET: out[k].sa.sin.sin_family = AF_INET; out[k].sa.sin.sin_port = htons(ports[j].port); memcpy(out[k].sa.sin.sin_addr, &addrs[i].addr, 4); break; case AF_INET6: out[k].sa.sin6.sin6_family = AF_INET6; out[k].sa.sin6.sin6_port = htons(ports[j].port); memcpy(out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); break; } } out[nais-1].ai_next = 0; *res = out; return 0; }
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.