simplify pthread_attr_t stack/guard size representation
[musl] / src / network / getaddrinfo.c
1 #include <stdlib.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <netdb.h>
5 #include <string.h>
6 #include "lookup.h"
7
8 int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
9 {
10         struct service ports[MAXSERVS];
11         struct address addrs[MAXADDRS];
12         char canon[256], *outcanon;
13         int nservs, naddrs, nais, canon_len, i, j, k;
14         int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
15         struct aibuf {
16                 struct addrinfo ai;
17                 union sa {
18                         struct sockaddr_in sin;
19                         struct sockaddr_in6 sin6;
20                 } sa;
21         } *out;
22
23         if (!host && !serv) return EAI_NONAME;
24
25         if (hint) {
26                 family = hint->ai_family;
27                 flags = hint->ai_flags;
28                 proto = hint->ai_protocol;
29                 socktype = hint->ai_socktype;
30
31                 const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
32                         AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
33                 if ((flags & mask) != flags)
34                         return EAI_BADFLAGS;
35
36                 switch (family) {
37                 case AF_INET:
38                 case AF_INET6:
39                 case AF_UNSPEC:
40                         break;
41                 default:
42                         return EAI_FAMILY;
43                 }
44         }
45
46         nservs = __lookup_serv(ports, serv, proto, socktype, flags);
47         if (nservs < 0) return nservs;
48
49         naddrs = __lookup_name(addrs, canon, host, family, flags);
50         if (naddrs < 0) return naddrs;
51
52         nais = nservs * naddrs;
53         canon_len = strlen(canon);
54         out = calloc(1, nais * sizeof(*out) + canon_len + 1);
55         if (!out) return EAI_MEMORY;
56
57         if (canon_len) {
58                 outcanon = (void *)&out[nais];
59                 memcpy(outcanon, canon, canon_len+1);
60         } else {
61                 outcanon = 0;
62         }
63
64         for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
65                 out[k].ai = (struct addrinfo){
66                         .ai_family = addrs[i].family,
67                         .ai_socktype = ports[j].socktype,
68                         .ai_protocol = ports[j].proto,
69                         .ai_addrlen = addrs[i].family == AF_INET
70                                 ? sizeof(struct sockaddr_in)
71                                 : sizeof(struct sockaddr_in6),
72                         .ai_addr = (void *)&out[k].sa,
73                         .ai_canonname = outcanon,
74                         .ai_next = &out[k+1].ai };
75                 switch (addrs[i].family) {
76                 case AF_INET:
77                         out[k].sa.sin.sin_family = AF_INET;
78                         out[k].sa.sin.sin_port = htons(ports[j].port);
79                         memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
80                         break;
81                 case AF_INET6:
82                         out[k].sa.sin6.sin6_family = AF_INET6;
83                         out[k].sa.sin6.sin6_port = htons(ports[j].port);
84                         out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;
85                         memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
86                         break;                  
87                 }
88         }
89         out[nais-1].ai.ai_next = 0;
90         *res = &out->ai;
91         return 0;
92 }