1 /*****************************************************************************
2 * getaddrinfo.c: getaddrinfo/getnameinfo replacement functions
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
5 * Copyright (C) 2002-2007 Rémi Denis-Courmont
6 * Copyright (C) 2011 KO Myung-Hun
8 * Authors: KO Myung-Hun <komh@chollian.net>
9 * Rémi Denis-Courmont <rem # videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_network.h>
33 #include <arpa/inet.h>
42 { EAI_BADFLAGS
, "Invalid flag used" },
43 { EAI_NONAME
, "Host or service not found" },
44 { EAI_AGAIN
, "Temporary name service failure" },
45 { EAI_FAIL
, "Non-recoverable name service failure" },
46 { EAI_NODATA
, "No data for host name" },
47 { EAI_FAMILY
, "Unsupported address family" },
48 { EAI_SOCKTYPE
, "Unsupported socket type" },
49 { EAI_SERVICE
, "Incompatible service for socket type" },
50 { EAI_ADDRFAMILY
, "Unavailable address family for host name" },
51 { EAI_MEMORY
, "Memory allocation failure" },
52 { EAI_OVERFLOW
, "Buffer overflow" },
53 { EAI_SYSTEM
, "System error" },
57 static const char gai_unknownerr
[] = "Unrecognized error number";
59 /****************************************************************************
60 * Converts an EAI_* error code into human readable english text.
61 ****************************************************************************/
62 const char *gai_strerror (int errnum
)
64 for (unsigned i
= 0; *gai_errlist
[i
].msg
; i
++)
65 if (errnum
== gai_errlist
[i
].code
)
66 return gai_errlist
[i
].msg
;
68 return gai_unknownerr
;
71 #define _NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|\
74 * getnameinfo() non-thread-safe IPv4-only implementation,
75 * Address-family-independent address to hostname translation
76 * (reverse DNS lookup in case of IPv4).
78 * This is meant for use on old IP-enabled systems that are not IPv6-aware,
79 * and probably do not have getnameinfo(), but have the old gethostbyaddr()
83 getnameinfo (const struct sockaddr
*sa
, socklen_t salen
,
84 char *host
, int hostlen
, char *serv
, int servlen
, int flags
)
86 if (((size_t)salen
< sizeof (struct sockaddr_in
))
87 || (sa
->sa_family
!= AF_INET
))
89 else if (flags
& (~_NI_MASK
))
93 const struct sockaddr_in
*addr
;
95 addr
= (const struct sockaddr_in
*)sa
;
99 /* host name resolution */
100 if (!(flags
& NI_NUMERICHOST
))
102 if (flags
& NI_NAMEREQD
)
106 /* inet_ntoa() is not thread-safe, do not use it */
107 uint32_t ipv4
= ntohl (addr
->sin_addr
.s_addr
);
109 if (snprintf (host
, hostlen
, "%u.%u.%u.%u", ipv4
>> 24,
110 (ipv4
>> 16) & 0xff, (ipv4
>> 8) & 0xff,
111 ipv4
& 0xff) >= (int)hostlen
)
117 if (snprintf (serv
, servlen
, "%u",
118 (unsigned int)ntohs (addr
->sin_port
)) >= (int)servlen
)
125 #define _AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
127 * Converts the current herrno error value into an EAI_* error code.
128 * That error code is normally returned by getnameinfo() or getaddrinfo().
131 gai_error_from_herrno (void)
139 # if (NO_ADDRESS != NO_DATA)
154 * This functions must be used to free the memory allocated by getaddrinfo().
156 void freeaddrinfo (struct addrinfo
*res
)
160 free (res
->ai_canonname
);
167 * Internal function that builds an addrinfo struct.
169 static struct addrinfo
*
170 makeaddrinfo (int af
, int type
, int proto
,
171 const struct sockaddr
*addr
, size_t addrlen
,
172 const char *canonname
)
174 struct addrinfo
*res
;
176 res
= (struct addrinfo
*)malloc (sizeof (struct addrinfo
));
181 res
->ai_socktype
= type
;
182 res
->ai_protocol
= proto
;
183 res
->ai_addrlen
= addrlen
;
184 res
->ai_addr
= malloc (addrlen
);
185 res
->ai_canonname
= NULL
;
188 if (res
->ai_addr
!= NULL
)
190 memcpy (res
->ai_addr
, addr
, addrlen
);
192 if (canonname
!= NULL
)
194 res
->ai_canonname
= strdup (canonname
);
195 if (res
->ai_canonname
!= NULL
)
196 return res
; /* success ! */
207 static struct addrinfo
*
208 makeipv4info (int type
, int proto
, u_long ip
, u_short port
, const char *name
)
210 struct sockaddr_in addr
;
212 memset (&addr
, 0, sizeof (addr
));
213 addr
.sin_family
= AF_INET
;
215 addr
.sin_len
= sizeof (addr
);
217 addr
.sin_port
= port
;
218 addr
.sin_addr
.s_addr
= ip
;
220 return makeaddrinfo (AF_INET
, type
, proto
,
221 (struct sockaddr
*)&addr
, sizeof (addr
), name
);
225 * getaddrinfo() non-thread-safe IPv4-only implementation
226 * Address-family-independent hostname to address resolution.
228 * This is meant for IPv6-unaware systems that do probably not provide
229 * getaddrinfo(), but still have old function gethostbyname().
231 * Only UDP and TCP over IPv4 are supported here.
234 getaddrinfo (const char *node
, const char *service
,
235 const struct addrinfo
*hints
, struct addrinfo
**res
)
237 struct addrinfo
*info
;
240 int protocol
= 0, flags
= 0;
241 const char *name
= NULL
;
245 flags
= hints
->ai_flags
;
247 if (flags
& ~_AI_MASK
)
249 /* only accept AF_INET and AF_UNSPEC */
250 if (hints
->ai_family
&& (hints
->ai_family
!= AF_INET
))
253 /* protocol sanity check */
254 switch (hints
->ai_socktype
)
257 protocol
= IPPROTO_TCP
;
261 protocol
= IPPROTO_UDP
;
273 if (hints
->ai_protocol
&& protocol
274 && (protocol
!= hints
->ai_protocol
))
283 if (flags
& AI_PASSIVE
)
284 ip
= htonl (INADDR_ANY
);
286 ip
= htonl (INADDR_LOOPBACK
);
289 if ((ip
= inet_addr (node
)) == INADDR_NONE
)
291 struct hostent
*entry
= NULL
;
293 /* hostname resolution */
294 if (!(flags
& AI_NUMERICHOST
))
295 entry
= gethostbyname (node
);
298 return gai_error_from_herrno ();
300 if ((entry
->h_length
!= 4) || (entry
->h_addrtype
!= AF_INET
))
303 ip
= *((u_long
*) entry
->h_addr
);
304 if (flags
& AI_CANONNAME
)
305 name
= entry
->h_name
;
308 if ((flags
& AI_CANONNAME
) && (name
== NULL
))
311 /* service resolution */
319 d
= strtoul (service
, &end
, 0);
320 if (end
[0] || (d
> 65535u))
323 port
= htons ((u_short
)d
);
326 /* building results... */
327 if ((!protocol
) || (protocol
== IPPROTO_UDP
))
329 info
= makeipv4info (SOCK_DGRAM
, IPPROTO_UDP
, ip
, port
, name
);
335 if (flags
& AI_PASSIVE
)
336 info
->ai_flags
|= AI_PASSIVE
;
339 if ((!protocol
) || (protocol
== IPPROTO_TCP
))
341 info
= makeipv4info (SOCK_STREAM
, IPPROTO_TCP
, ip
, port
, name
);
347 info
->ai_next
= *res
;
348 if (flags
& AI_PASSIVE
)
349 info
->ai_flags
|= AI_PASSIVE
;