summaryrefslogtreecommitdiff
path: root/src/network/lookup_serv.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2014-05-31 20:57:54 -0400
committerRich Felker <dalias@aerifal.cx>2014-05-31 20:57:54 -0400
commit6f409bff008a83fa6bc640c10366765874de35e2 (patch)
tree4c192acbf8bdd019719dd9536cc3eaae0de3696c /src/network/lookup_serv.c
parent5f4c4966934b913e9f8a54d60312f874a9d14088 (diff)
downloadmusl-6f409bff008a83fa6bc640c10366765874de35e2.tar.gz
refactor getaddrinfo and add support for most remaining features
this is the first phase of the "resolver overhaul" project. conceptually, the results of getaddrinfo are a direct product of a list of address results and a list of service results. the new code makes this explicit by computing these lists separately and combining the results. this adds support for services that have both tcp and udp versions, where the caller has not specified which it wants, and eliminates a number of duplicate code paths which were all producing the final output addrinfo structures, but in subtly different ways, making it difficult to implement any of the features which were missing. in addition to the above benefits, the refactoring allows for legacy functions like gethostbyname to be implemented without using the getaddrinfo function itself. such changes to the legacy functions have not yet been made, however. further improvements include matching of service alias names from /etc/services (previously only the primary name was supported), returning multiple results from /etc/hosts (previously only the first matching line was honored), and support for the AI_V4MAPPED and AI_ALL flags. features which remain unimplemented are IDN translations (encoding non-ASCII hostnames for DNS lookup) and the AI_ADDRCONFIG flag. at this point, the DNS-based name resolving code is still based on the old interfaces in __dns.c, albeit somewhat simpler in its use of them. there may be some dead code which could already be removed, but changes to this layer will be a later phase of the resolver overhaul.
Diffstat (limited to 'src/network/lookup_serv.c')
-rw-r--r--src/network/lookup_serv.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/network/lookup_serv.c b/src/network/lookup_serv.c
new file mode 100644
index 00000000..bf4cba09
--- /dev/null
+++ b/src/network/lookup_serv.c
@@ -0,0 +1,72 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include "lookup.h"
+#include "stdio_impl.h"
+
+int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags)
+{
+ char line[128];
+ int cnt = 0;
+ char *p, *z = "";
+ unsigned long port = 0;
+
+ if (name) {
+ if (!*name) return EAI_SERVICE;
+ port = strtoul(name, &z, 10);
+ }
+ if (!*z) {
+ if (port > 65535) return EAI_SERVICE;
+ if (proto != IPPROTO_UDP) {
+ buf[cnt].port = port;
+ buf[cnt++].proto = IPPROTO_TCP;
+ }
+ if (proto != IPPROTO_TCP) {
+ buf[cnt].port = port;
+ buf[cnt++].proto = IPPROTO_UDP;
+ }
+ return cnt;
+ }
+
+ if (flags & AI_NUMERICSERV) return EAI_SERVICE;
+
+ size_t l = strlen(name);
+
+ unsigned char _buf[1032];
+ FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
+ if (!f) return EAI_SERVICE;
+
+ while (fgets(line, sizeof line, f) && cnt < MAXSERVS) {
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+
+ /* Find service name */
+ for(p=line; (p=strstr(p, name)); p++) {
+ if (p>line && !isspace(p[-1])) continue;
+ if (p[l] && !isspace(p[l])) continue;
+ break;
+ }
+ if (!p) continue;
+
+ /* Skip past canonical name at beginning of line */
+ for (p=line; *p && !isspace(*p); p++);
+ if (!p) continue;
+
+ port = strtoul(p, &z, 10);
+ if (port > 65535 || z==p) continue;
+ if (!strncmp(z, "/udp", 4)) {
+ if (proto == IPPROTO_TCP) continue;
+ buf[cnt].port = port;
+ buf[cnt++].proto = IPPROTO_UDP;
+ }
+ if (!strncmp(z, "/tcp", 4)) {
+ if (proto == IPPROTO_UDP) continue;
+ buf[cnt].port = port;
+ buf[cnt++].proto = IPPROTO_TCP;
+ }
+ }
+ __fclose_ca(f);
+ return cnt > 0 ? cnt : EAI_SERVICE;
+}