improve getservbyname_r using new resolver backend
authorRich Felker <dalias@aerifal.cx>
Sun, 1 Jun 2014 04:45:04 +0000 (00:45 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 1 Jun 2014 04:45:04 +0000 (00:45 -0400)
now that host and service lookup have been separated in the backend,
there's no need for service lookup functions to pull in the host
lookup code. moreover, dynamic allocation is no longer needed, so this
function should now be async-signal-safe. it's also significantly
smaller.

one change in getservbyname is also made: knowing that getservbyname_r
needs only two character pointers in the caller-provided buffer, some
wasted bss can be avoided.

src/network/getservbyname.c
src/network/getservbyname_r.c

index 0b00ce11da82ba08403b207275ad6ecf923b7fb7..dd3037678c278536ce51cf6f296fc512175e7322 100644 (file)
@@ -4,7 +4,7 @@
 struct servent *getservbyname(const char *name, const char *prots)
 {
        static struct servent se;
-       static long buf[32/sizeof(long)];
+       static char *buf[2];
        struct servent *res;
        if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res))
                return 0;
index 811c174c8bc209aebb5fb2118ae3218be993542b..8cdf622c06124acd7227839fcefb3e8393f892ce 100644 (file)
@@ -5,49 +5,43 @@
 #include <inttypes.h>
 #include <errno.h>
 #include <string.h>
+#include "lookup.h"
+
+#define ALIGN (sizeof(struct { char a; char *b; }) - sizeof(char *))
 
 int getservbyname_r(const char *name, const char *prots,
        struct servent *se, char *buf, size_t buflen, struct servent **res)
 {
-       struct addrinfo *ai, hint = { .ai_family = AF_INET };
-       int i;
-
-       if (!prots) {
-               int r = getservbyname_r(name, "tcp", se, buf, buflen, res);
-               if (r) r = getservbyname_r(name, "udp", se, buf, buflen, res);
-               return r;
-       }
+       struct service servs[MAXSERVS];
+       int cnt, proto, align;
 
        /* Align buffer */
-       i = (uintptr_t)buf & sizeof(char *)-1;
-       if (!i) i = sizeof(char *);
-       if (buflen < 3*sizeof(char *)-i)
+       align = -(uintptr_t)buf & ALIGN-1;
+       if (buflen < 2*sizeof(char *)+align)
                return ERANGE;
-       buf += sizeof(char *)-i;
-       buflen -= sizeof(char *)-i;
+       buf += align;
 
-       if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP;
-       else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP;
+       if (!prots) proto = 0;
+       else if (!strcmp(prots, "tcp")) proto = IPPROTO_TCP;
+       else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP;
        else return EINVAL;
 
-       switch (getaddrinfo(0, name, &hint, &ai)) {
+       cnt = __lookup_serv(servs, name, proto, 0);
+       if (cnt<0) switch (cnt) {
        case EAI_MEMORY:
        case EAI_SYSTEM:
                return ENOMEM;
        default:
                return ENOENT;
-       case 0:
-               break;
        }
 
        se->s_name = (char *)name;
        se->s_aliases = (void *)buf;
        se->s_aliases[0] = se->s_name;
        se->s_aliases[1] = 0;
-       se->s_port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
-       se->s_proto = (char *)prots;
+       se->s_port = htons(servs[0].port);
+       se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp";
 
-       freeaddrinfo(ai);
        *res = se;
        return 0;
 }