summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2014-06-01 00:45:04 -0400
committerRich Felker <dalias@aerifal.cx>2014-06-01 00:45:04 -0400
commitaf7c308ee66c4127700dd7843f885f7f2d030a0c (patch)
tree02e103e0e40c463b367edae7cc3ae63840c4afdc
parente8f39ca4898237cf71657500f0b11534c47a0521 (diff)
downloadmusl-af7c308ee66c4127700dd7843f885f7f2d030a0c.tar.gz
improve getservbyname_r using new resolver backend
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.
-rw-r--r--src/network/getservbyname.c2
-rw-r--r--src/network/getservbyname_r.c36
2 files changed, 16 insertions, 22 deletions
diff --git a/src/network/getservbyname.c b/src/network/getservbyname.c
index 0b00ce11..dd303767 100644
--- a/src/network/getservbyname.c
+++ b/src/network/getservbyname.c
@@ -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;
diff --git a/src/network/getservbyname_r.c b/src/network/getservbyname_r.c
index 811c174c..8cdf622c 100644
--- a/src/network/getservbyname_r.c
+++ b/src/network/getservbyname_r.c
@@ -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;
}