getaddrinfo.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* Get address information (partial implementation).
  2. Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software
  3. Foundation, Inc.
  4. Contributed by Simon Josefsson <simon@josefsson.org>.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  16. #include <config.h>
  17. #include "getaddrinfo.h"
  18. #if HAVE_NETINET_IN_H
  19. # include <netinet/in.h>
  20. #endif
  21. /* Get calloc. */
  22. #include <stdlib.h>
  23. /* Get memcpy. */
  24. #include <string.h>
  25. #include <stdbool.h>
  26. #include "gettext.h"
  27. #define _(String) gettext (String)
  28. #define N_(String) String
  29. #include "inet_ntop.h"
  30. #include "snprintf.h"
  31. #include "strdup.h"
  32. /* BeOS has AF_INET, but not PF_INET. */
  33. #ifndef PF_INET
  34. # define PF_INET AF_INET
  35. #endif
  36. /* BeOS also lacks PF_UNSPEC. */
  37. #ifndef PF_UNSPEC
  38. # define PF_UNSPEC 0
  39. #endif
  40. #if defined _WIN32 || defined __WIN32__
  41. # define WIN32_NATIVE
  42. #endif
  43. #ifdef WIN32_NATIVE
  44. typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
  45. const struct addrinfo*,
  46. struct addrinfo**);
  47. typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
  48. typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
  49. socklen_t, char*, DWORD,
  50. char*, DWORD, int);
  51. static getaddrinfo_func getaddrinfo_ptr = NULL;
  52. static freeaddrinfo_func freeaddrinfo_ptr = NULL;
  53. static getnameinfo_func getnameinfo_ptr = NULL;
  54. static int
  55. use_win32_p (void)
  56. {
  57. static int done = 0;
  58. HMODULE h;
  59. if (done)
  60. return getaddrinfo_ptr ? 1 : 0;
  61. done = 1;
  62. h = GetModuleHandle ("ws2_32.dll");
  63. if (h)
  64. {
  65. getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo");
  66. freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo");
  67. getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo");
  68. }
  69. /* If either is missing, something is odd. */
  70. if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
  71. {
  72. getaddrinfo_ptr = NULL;
  73. freeaddrinfo_ptr = NULL;
  74. getnameinfo_ptr = NULL;
  75. return 0;
  76. }
  77. return 1;
  78. }
  79. #endif
  80. static inline bool
  81. validate_family (int family)
  82. {
  83. /* FIXME: Support more families. */
  84. #if HAVE_IPV4
  85. if (family == PF_INET)
  86. return true;
  87. #endif
  88. #if HAVE_IPV6
  89. if (family == PF_INET6)
  90. return true;
  91. #endif
  92. if (family == PF_UNSPEC)
  93. return true;
  94. return false;
  95. }
  96. /* Translate name of a service location and/or a service name to set of
  97. socket addresses. */
  98. int
  99. getaddrinfo (const char *restrict nodename,
  100. const char *restrict servname,
  101. const struct addrinfo *restrict hints,
  102. struct addrinfo **restrict res)
  103. {
  104. struct addrinfo *tmp;
  105. int port = 0;
  106. struct hostent *he;
  107. void *storage;
  108. size_t size;
  109. #if HAVE_IPV6
  110. struct v6_pair {
  111. struct addrinfo addrinfo;
  112. struct sockaddr_in6 sockaddr_in6;
  113. };
  114. #endif
  115. #if HAVE_IPV4
  116. struct v4_pair {
  117. struct addrinfo addrinfo;
  118. struct sockaddr_in sockaddr_in;
  119. };
  120. #endif
  121. #ifdef WIN32_NATIVE
  122. if (use_win32_p ())
  123. return getaddrinfo_ptr (nodename, servname, hints, res);
  124. #endif
  125. if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
  126. /* FIXME: Support more flags. */
  127. return EAI_BADFLAGS;
  128. if (hints && !validate_family (hints->ai_family))
  129. return EAI_FAMILY;
  130. if (hints &&
  131. hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
  132. /* FIXME: Support other socktype. */
  133. return EAI_SOCKTYPE; /* FIXME: Better return code? */
  134. if (!nodename)
  135. {
  136. if (!(hints->ai_flags & AI_PASSIVE))
  137. return EAI_NONAME;
  138. #ifdef HAVE_IPV6
  139. nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
  140. #else
  141. nodename = "0.0.0.0";
  142. #endif
  143. }
  144. if (servname)
  145. {
  146. struct servent *se = NULL;
  147. const char *proto =
  148. (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
  149. if (!(hints->ai_flags & AI_NUMERICSERV))
  150. /* FIXME: Use getservbyname_r if available. */
  151. se = getservbyname (servname, proto);
  152. if (!se)
  153. {
  154. char *c;
  155. if (!(*servname >= '0' && *servname <= '9'))
  156. return EAI_NONAME;
  157. port = strtoul (servname, &c, 10);
  158. if (*c || port > 0xffff)
  159. return EAI_NONAME;
  160. port = htons (port);
  161. }
  162. else
  163. port = se->s_port;
  164. }
  165. /* FIXME: Use gethostbyname_r if available. */
  166. he = gethostbyname (nodename);
  167. if (!he || he->h_addr_list[0] == NULL)
  168. return EAI_NONAME;
  169. switch (he->h_addrtype)
  170. {
  171. #if HAVE_IPV6
  172. case PF_INET6:
  173. size = sizeof (struct v6_pair);
  174. break;
  175. #endif
  176. #if HAVE_IPV4
  177. case PF_INET:
  178. size = sizeof (struct v4_pair);
  179. break;
  180. #endif
  181. default:
  182. return EAI_NODATA;
  183. }
  184. storage = calloc (1, size);
  185. if (!storage)
  186. return EAI_MEMORY;
  187. switch (he->h_addrtype)
  188. {
  189. #if HAVE_IPV6
  190. case PF_INET6:
  191. {
  192. struct v6_pair *p = storage;
  193. struct sockaddr_in6 *sinp = &p->sockaddr_in6;
  194. tmp = &p->addrinfo;
  195. if (port)
  196. sinp->sin6_port = port;
  197. if (he->h_length != sizeof (sinp->sin6_addr))
  198. {
  199. free (storage);
  200. return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
  201. }
  202. memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
  203. tmp->ai_addr = (struct sockaddr *) sinp;
  204. tmp->ai_addrlen = sizeof *sinp;
  205. }
  206. break;
  207. #endif
  208. #if HAVE_IPV4
  209. case PF_INET:
  210. {
  211. struct v4_pair *p = storage;
  212. struct sockaddr_in *sinp = &p->sockaddr_in;
  213. tmp = &p->addrinfo;
  214. if (port)
  215. sinp->sin_port = port;
  216. if (he->h_length != sizeof (sinp->sin_addr))
  217. {
  218. free (storage);
  219. return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
  220. }
  221. memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
  222. tmp->ai_addr = (struct sockaddr *) sinp;
  223. tmp->ai_addrlen = sizeof *sinp;
  224. }
  225. break;
  226. #endif
  227. default:
  228. free (storage);
  229. return EAI_NODATA;
  230. }
  231. if (hints && hints->ai_flags & AI_CANONNAME)
  232. {
  233. const char *cn;
  234. if (he->h_name)
  235. cn = he->h_name;
  236. else
  237. cn = nodename;
  238. tmp->ai_canonname = strdup (cn);
  239. if (!tmp->ai_canonname)
  240. {
  241. free (storage);
  242. return EAI_MEMORY;
  243. }
  244. }
  245. tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
  246. tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
  247. tmp->ai_addr->sa_family = he->h_addrtype;
  248. tmp->ai_family = he->h_addrtype;
  249. /* FIXME: If more than one address, create linked list of addrinfo's. */
  250. *res = tmp;
  251. return 0;
  252. }
  253. /* Free `addrinfo' structure AI including associated storage. */
  254. void
  255. freeaddrinfo (struct addrinfo *ai)
  256. {
  257. #ifdef WIN32_NATIVE
  258. if (use_win32_p ())
  259. {
  260. freeaddrinfo_ptr (ai);
  261. return;
  262. }
  263. #endif
  264. while (ai)
  265. {
  266. struct addrinfo *cur;
  267. cur = ai;
  268. ai = ai->ai_next;
  269. if (cur->ai_canonname) free (cur->ai_canonname);
  270. free (cur);
  271. }
  272. }
  273. int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
  274. char *restrict node, socklen_t nodelen,
  275. char *restrict service, socklen_t servicelen,
  276. int flags)
  277. {
  278. #ifdef WIN32_NATIVE
  279. if (use_win32_p ())
  280. return getnameinfo_ptr (sa, salen, node, nodelen,
  281. service, servicelen, flags);
  282. #endif
  283. /* FIXME: Support other flags. */
  284. if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
  285. (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
  286. (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
  287. return EAI_BADFLAGS;
  288. if (sa == NULL || salen < sizeof (sa->sa_family))
  289. return EAI_FAMILY;
  290. switch (sa->sa_family)
  291. {
  292. #if HAVE_IPV4
  293. case AF_INET:
  294. if (salen < sizeof (struct sockaddr_in))
  295. return EAI_FAMILY;
  296. break;
  297. #endif
  298. #if HAVE_IPV6
  299. case AF_INET6:
  300. if (salen < sizeof (struct sockaddr_in6))
  301. return EAI_FAMILY;
  302. break;
  303. #endif
  304. default:
  305. return EAI_FAMILY;
  306. }
  307. if (node && nodelen > 0 && flags & NI_NUMERICHOST)
  308. {
  309. switch (sa->sa_family)
  310. {
  311. #if HAVE_IPV4
  312. case AF_INET:
  313. if (!inet_ntop (AF_INET,
  314. &(((const struct sockaddr_in *) sa)->sin_addr),
  315. node, nodelen))
  316. return EAI_SYSTEM;
  317. break;
  318. #endif
  319. #if HAVE_IPV6
  320. case AF_INET6:
  321. if (!inet_ntop (AF_INET6,
  322. &(((const struct sockaddr_in6 *) sa)->sin6_addr),
  323. node, nodelen))
  324. return EAI_SYSTEM;
  325. break;
  326. #endif
  327. default:
  328. return EAI_FAMILY;
  329. }
  330. }
  331. if (service && servicelen > 0 && flags & NI_NUMERICSERV)
  332. switch (sa->sa_family)
  333. {
  334. #if HAVE_IPV4
  335. case AF_INET:
  336. #endif
  337. #if HAVE_IPV6
  338. case AF_INET6:
  339. #endif
  340. {
  341. unsigned short int port
  342. = ntohs (((const struct sockaddr_in *) sa)->sin_port);
  343. if (servicelen <= snprintf (service, servicelen, "%u", port))
  344. return EAI_OVERFLOW;
  345. }
  346. break;
  347. }
  348. return 0;
  349. }