2 #include <sys/socket.h>
3 #include <netinet/in.h>
12 int getaddrinfo(const char *restrict host
, const char *restrict serv
, const struct addrinfo
*restrict hint
, struct addrinfo
**restrict res
)
14 struct service ports
[MAXSERVS
];
15 struct address addrs
[MAXADDRS
];
16 char canon
[256], *outcanon
;
17 int nservs
, naddrs
, nais
, canon_len
, i
, j
, k
;
18 int family
= AF_UNSPEC
, flags
= 0, proto
= 0, socktype
= 0;
22 if (!host
&& !serv
) return EAI_NONAME
;
25 family
= hint
->ai_family
;
26 flags
= hint
->ai_flags
;
27 proto
= hint
->ai_protocol
;
28 socktype
= hint
->ai_socktype
;
30 const int mask
= AI_PASSIVE
| AI_CANONNAME
| AI_NUMERICHOST
|
31 AI_V4MAPPED
| AI_ALL
| AI_ADDRCONFIG
| AI_NUMERICSERV
;
32 if ((flags
& mask
) != flags
)
45 if (flags
& AI_ADDRCONFIG
) {
46 /* Define the "an address is configured" condition for address
47 * families via ability to create a socket for the family plus
48 * routability of the loopback address for the family. */
49 static const struct sockaddr_in lo4
= {
50 .sin_family
= AF_INET
, .sin_port
= 65535,
51 .sin_addr
.s_addr
= __BYTE_ORDER
== __BIG_ENDIAN
52 ? 0x7f000001 : 0x0100007f
54 static const struct sockaddr_in6 lo6
= {
55 .sin6_family
= AF_INET6
, .sin6_port
= 65535,
56 .sin6_addr
= IN6ADDR_LOOPBACK_INIT
58 int tf
[2] = { AF_INET
, AF_INET6
};
59 const void *ta
[2] = { &lo4
, &lo6
};
60 socklen_t tl
[2] = { sizeof lo4
, sizeof lo6
};
62 if (family
==tf
[1-i
]) continue;
63 int s
= socket(tf
[i
], SOCK_CLOEXEC
|SOCK_DGRAM
,
67 pthread_setcancelstate(
68 PTHREAD_CANCEL_DISABLE
, &cs
);
69 int r
= connect(s
, ta
[i
], tl
[i
]);
70 int saved_errno
= errno
;
71 pthread_setcancelstate(cs
, 0);
86 if (family
== tf
[i
]) no_family
= 1;
91 nservs
= __lookup_serv(ports
, serv
, proto
, socktype
, flags
);
92 if (nservs
< 0) return nservs
;
94 naddrs
= __lookup_name(addrs
, canon
, host
, family
, flags
);
95 if (naddrs
< 0) return naddrs
;
97 if (no_family
) return EAI_NODATA
;
99 nais
= nservs
* naddrs
;
100 canon_len
= strlen(canon
);
101 out
= calloc(1, nais
* sizeof(*out
) + canon_len
+ 1);
102 if (!out
) return EAI_MEMORY
;
105 outcanon
= (void *)&out
[nais
];
106 memcpy(outcanon
, canon
, canon_len
+1);
111 for (k
=i
=0; i
<naddrs
; i
++) for (j
=0; j
<nservs
; j
++, k
++) {
113 out
[k
].ai
= (struct addrinfo
){
114 .ai_family
= addrs
[i
].family
,
115 .ai_socktype
= ports
[j
].socktype
,
116 .ai_protocol
= ports
[j
].proto
,
117 .ai_addrlen
= addrs
[i
].family
== AF_INET
118 ? sizeof(struct sockaddr_in
)
119 : sizeof(struct sockaddr_in6
),
120 .ai_addr
= (void *)&out
[k
].sa
,
121 .ai_canonname
= outcanon
};
122 if (k
) out
[k
-1].ai
.ai_next
= &out
[k
].ai
;
123 switch (addrs
[i
].family
) {
125 out
[k
].sa
.sin
.sin_family
= AF_INET
;
126 out
[k
].sa
.sin
.sin_port
= htons(ports
[j
].port
);
127 memcpy(&out
[k
].sa
.sin
.sin_addr
, &addrs
[i
].addr
, 4);
130 out
[k
].sa
.sin6
.sin6_family
= AF_INET6
;
131 out
[k
].sa
.sin6
.sin6_port
= htons(ports
[j
].port
);
132 out
[k
].sa
.sin6
.sin6_scope_id
= addrs
[i
].scopeid
;
133 memcpy(&out
[k
].sa
.sin6
.sin6_addr
, &addrs
[i
].addr
, 16);