22 |
|
|
23 |
#include "getaddrinfo.h" |
#include "getaddrinfo.h" |
24 |
|
|
25 |
|
#if HAVE_NETINET_IN_H |
26 |
|
# include <netinet/in.h> |
27 |
|
#endif |
28 |
|
|
29 |
/* Get calloc. */ |
/* Get calloc. */ |
30 |
#include <stdlib.h> |
#include <stdlib.h> |
31 |
|
|
66 |
struct addrinfo **restrict res) |
struct addrinfo **restrict res) |
67 |
{ |
{ |
68 |
struct addrinfo *tmp; |
struct addrinfo *tmp; |
69 |
struct servent *se; |
struct servent *se = NULL; |
70 |
struct hostent *he; |
struct hostent *he; |
71 |
size_t sinlen; |
void *storage; |
72 |
|
size_t size; |
73 |
|
#if HAVE_IPV6 |
74 |
|
struct v6_pair { |
75 |
|
struct addrinfo addrinfo; |
76 |
|
struct sockaddr_in6 sockaddr_in6; |
77 |
|
}; |
78 |
|
#endif |
79 |
|
#if HAVE_IPV4 |
80 |
|
struct v4_pair { |
81 |
|
struct addrinfo addrinfo; |
82 |
|
struct sockaddr_in sockaddr_in; |
83 |
|
}; |
84 |
|
#endif |
85 |
|
|
86 |
if (hints && (hints->ai_flags & ~AI_CANONNAME)) |
if (hints && (hints->ai_flags & ~AI_CANONNAME)) |
87 |
/* FIXME: Support more flags. */ |
/* FIXME: Support more flags. */ |
120 |
{ |
{ |
121 |
#if HAVE_IPV6 |
#if HAVE_IPV6 |
122 |
case PF_INET6: |
case PF_INET6: |
123 |
sinlen = sizeof (struct sockaddr_in6); |
size = sizeof (struct v6_pair); |
124 |
break; |
break; |
125 |
#endif |
#endif |
126 |
|
|
127 |
#if HAVE_IPV4 |
#if HAVE_IPV4 |
128 |
case PF_INET: |
case PF_INET: |
129 |
sinlen = sizeof (struct sockaddr_in); |
size = sizeof (struct v4_pair); |
130 |
break; |
break; |
131 |
#endif |
#endif |
132 |
|
|
134 |
return EAI_NODATA; |
return EAI_NODATA; |
135 |
} |
} |
136 |
|
|
137 |
tmp = calloc (1, sizeof (*tmp) + sinlen); |
storage = calloc (1, size); |
138 |
if (!tmp) |
if (!storage) |
139 |
return EAI_MEMORY; |
return EAI_MEMORY; |
140 |
|
|
141 |
switch (he->h_addrtype) |
switch (he->h_addrtype) |
143 |
#if HAVE_IPV6 |
#if HAVE_IPV6 |
144 |
case PF_INET6: |
case PF_INET6: |
145 |
{ |
{ |
146 |
struct sockaddr_in6 *sinp = (char *) tmp + sizeof (*tmp); |
struct v6_pair *p = storage; |
147 |
|
struct sockaddr_in6 *sinp = &p->sockaddr_in6; |
148 |
|
tmp = &p->addrinfo; |
149 |
|
|
150 |
if (se) |
if (se) |
151 |
sinp->sin6_port = se->s_port; |
sinp->sin6_port = se->s_port; |
152 |
|
|
153 |
if (he->h_length != sizeof (sinp->sin6_addr)) |
if (he->h_length != sizeof (sinp->sin6_addr)) |
154 |
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ |
{ |
155 |
|
free (storage); |
156 |
|
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ |
157 |
|
} |
158 |
|
|
159 |
memcpy (&sinp->sin6_addr, he->h_addr_list[0], he->h_length); |
memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr); |
160 |
|
|
161 |
tmp->ai_addr = (struct sockaddr *) sinp; |
tmp->ai_addr = (struct sockaddr *) sinp; |
162 |
tmp->ai_addrlen = sinlen; |
tmp->ai_addrlen = sizeof *sinp; |
163 |
} |
} |
164 |
break; |
break; |
165 |
#endif |
#endif |
167 |
#if HAVE_IPV4 |
#if HAVE_IPV4 |
168 |
case PF_INET: |
case PF_INET: |
169 |
{ |
{ |
170 |
struct sockaddr_in *sinp = (char *) tmp + sizeof (*tmp); |
struct v4_pair *p = storage; |
171 |
|
struct sockaddr_in *sinp = &p->sockaddr_in; |
172 |
|
tmp = &p->addrinfo; |
173 |
|
|
174 |
if (se) |
if (se) |
175 |
sinp->sin_port = se->s_port; |
sinp->sin_port = se->s_port; |
176 |
|
|
177 |
if (he->h_length != sizeof (sinp->sin_addr)) |
if (he->h_length != sizeof (sinp->sin_addr)) |
178 |
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ |
{ |
179 |
|
free (storage); |
180 |
|
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ |
181 |
|
} |
182 |
|
|
183 |
memcpy (&sinp->sin_addr, he->h_addr_list[0], he->h_length); |
memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr); |
184 |
|
|
185 |
tmp->ai_addr = (struct sockaddr *) sinp; |
tmp->ai_addr = (struct sockaddr *) sinp; |
186 |
tmp->ai_addrlen = sinlen; |
tmp->ai_addrlen = sizeof *sinp; |
187 |
} |
} |
188 |
break; |
break; |
189 |
#endif |
#endif |
190 |
|
|
191 |
default: |
default: |
192 |
free (tmp); |
free (storage); |
193 |
return EAI_NODATA; |
return EAI_NODATA; |
194 |
} |
} |
195 |
|
|
204 |
tmp->ai_canonname = strdup (cn); |
tmp->ai_canonname = strdup (cn); |
205 |
if (!tmp->ai_canonname) |
if (!tmp->ai_canonname) |
206 |
{ |
{ |
207 |
free (tmp); |
free (storage); |
208 |
return EAI_MEMORY; |
return EAI_MEMORY; |
209 |
} |
} |
210 |
} |
} |