gaih_inet: Simplify service resolution

Refactor the code to split out the service resolution code into a
separate function.  Allocate the service tuples array just once to the
size of the typeproto array, thus avoiding the unnecessary pointer
chasing and stack allocations.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
This commit is contained in:
Siddhesh Poyarekar 2022-02-10 13:27:11 +05:30
parent 3004604607
commit 8d6cf99f2f

View File

@ -100,14 +100,12 @@ struct gaih_service
struct gaih_servtuple
{
struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
bool set;
};
static const struct gaih_servtuple nullserv;
struct gaih_typeproto
{
@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
while (r);
st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = s->s_port;
st->set = true;
return 0;
}
@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
}
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
unsigned int *naddrs, struct scratch_buffer *tmpbuf)
get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
{
int i;
const struct gaih_typeproto *tp = gaih_inet_typeproto;
struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
function. */
size_t alloca_used = sizeof (struct scratch_buffer);
if (req->ai_protocol || req->ai_socktype)
{
@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
int port = 0;
if (service != NULL)
if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
return -EAI_SERVICE;
if (service == NULL || service->num >= 0)
{
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
return -EAI_SERVICE;
if (service->num < 0)
{
if (tp->name[0])
{
st = (struct gaih_servtuple *)
alloca_account (sizeof (struct gaih_servtuple), alloca_used);
int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
if (__glibc_unlikely (rc != 0))
return rc;
}
else
{
struct gaih_servtuple **pst = &st;
for (tp++; tp->name[0]; tp++)
{
struct gaih_servtuple *newp;
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
continue;
if (req->ai_socktype != 0
&& req->ai_socktype != tp->socktype)
continue;
if (req->ai_protocol != 0
&& !(tp->protoflag & GAI_PROTO_PROTOANY)
&& req->ai_protocol != tp->protocol)
continue;
newp = (struct gaih_servtuple *)
alloca_account (sizeof (struct gaih_servtuple),
alloca_used);
if (gaih_inet_serv (service->name,
tp, req, newp, tmpbuf) != 0)
continue;
*pst = newp;
pst = &(newp->next);
}
if (st == (struct gaih_servtuple *) &nullserv)
return -EAI_SERVICE;
}
}
else
{
port = htons (service->num);
goto got_port;
}
}
else
{
got_port:
int port = service != NULL ? htons (service->num) : 0;
if (req->ai_socktype || req->ai_protocol)
{
st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
st[0].socktype = tp->socktype;
st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = port;
}
else
{
/* Neither socket type nor protocol is set. Return all socket types
we know about. */
struct gaih_servtuple **lastp = &st;
for (++tp; tp->name[0]; ++tp)
if (tp->defaultflag)
{
struct gaih_servtuple *newp;
st[0].port = port;
st[0].set = true;
newp = alloca_account (sizeof (struct gaih_servtuple),
alloca_used);
newp->next = NULL;
newp->socktype = tp->socktype;
newp->protocol = tp->protocol;
newp->port = port;
*lastp = newp;
lastp = &newp->next;
}
return 0;
}
/* Neither socket type nor protocol is set. Return all socket types
we know about. */
for (i = 0, ++tp; tp->name[0]; ++tp)
if (tp->defaultflag)
{
st[i].socktype = tp->socktype;
st[i].protocol = tp->protocol;
st[i].port = port;
st[i++].set = true;
}
return 0;
}
if (tp->name[0])
return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
for (i = 0, tp++; tp->name[0]; tp++)
{
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
continue;
if (req->ai_socktype != 0
&& req->ai_socktype != tp->socktype)
continue;
if (req->ai_protocol != 0
&& !(tp->protoflag & GAI_PROTO_PROTOANY)
&& req->ai_protocol != tp->protocol)
continue;
if (gaih_inet_serv (service->name,
tp, req, &st[i], tmpbuf) != 0)
continue;
i++;
}
if (!st[0].set)
return -EAI_SERVICE;
return 0;
}
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
unsigned int *naddrs, struct scratch_buffer *tmpbuf)
{
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
/ sizeof (struct gaih_typeproto)] = {0};
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
function. */
size_t alloca_used = sizeof (struct scratch_buffer);
int rc;
if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
return rc;
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
@ -1083,7 +1062,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((result = process_canonname (req, orig_name, &canon)) != 0)
goto free_and_return;
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
sa_family_t family;
@ -1109,7 +1087,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
socklen = sizeof (struct sockaddr_in);
for (st2 = st; st2 != NULL; st2 = st2->next)
for (int i = 0; st[i].set; i++)
{
struct addrinfo *ai;
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
@ -1121,8 +1099,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_flags = req->ai_flags;
ai->ai_family = family;
ai->ai_socktype = st2->socktype;
ai->ai_protocol = st2->protocol;
ai->ai_socktype = st[i].socktype;
ai->ai_protocol = st[i].protocol;
ai->ai_addrlen = socklen;
ai->ai_addr = (void *) (ai + 1);
@ -1144,7 +1122,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) ai->ai_addr;
sin6p->sin6_port = st2->port;
sin6p->sin6_port = st[i].port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
@ -1154,7 +1132,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) ai->ai_addr;
sinp->sin_port = st2->port;
sinp->sin_port = st[i].port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));