getaddrinfo.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* include ga1 */
  2. #include "gai_hdr.h"
  3. #include <arpa/nameser.h> /* needed for <resolv.h> */
  4. #include <resolv.h> /* res_init, _res */
  5. int
  6. getaddrinfo(const char *hostname, const char *servname,
  7. const struct addrinfo *hintsp, struct addrinfo **result)
  8. {
  9. int rc, error, nsearch;
  10. char **ap, *canon;
  11. struct hostent *hptr;
  12. struct search search[3], *sptr;
  13. struct addrinfo hints, *aihead, **aipnext;
  14. /*
  15. * If we encounter an error we want to free() any dynamic memory
  16. * that we've allocated. This is our hack to simplify the code.
  17. */
  18. #define error(e) { error = (e); goto bad; }
  19. aihead = NULL; /* initialize automatic variables */
  20. aipnext = &aihead;
  21. canon = NULL;
  22. if (hintsp == NULL) {
  23. bzero(&hints, sizeof(hints));
  24. hints.ai_family = AF_UNSPEC;
  25. } else
  26. hints = *hintsp; /* struct copy */
  27. /* 4first some basic error checking */
  28. if ( (rc = ga_echeck(hostname, servname, hints.ai_flags, hints.ai_family,
  29. hints.ai_socktype, hints.ai_protocol)) != 0)
  30. error(rc);
  31. #ifdef UNIXdomain
  32. /* 4special case Unix domain first */
  33. if (hostname != NULL &&
  34. (strcmp(hostname, "/local") == 0 || strcmp(hostname, "/unix") == 0) &&
  35. (servname != NULL && servname[0] == '/'))
  36. return(ga_unix(servname, &hints, result));
  37. #endif
  38. /* end ga1 */
  39. /* include ga3 */
  40. /* 4remainder of function for IPv4/IPv6 */
  41. nsearch = ga_nsearch(hostname, &hints, &search[0]);
  42. for (sptr = &search[0]; sptr < &search[nsearch]; sptr++) {
  43. #ifdef IPv4
  44. /* 4check for an IPv4 dotted-decimal string */
  45. if (isdigit(sptr->host[0])) {
  46. struct in_addr inaddr;
  47. if (inet_pton(AF_INET, sptr->host, &inaddr) == 1) {
  48. if (hints.ai_family != AF_UNSPEC &&
  49. hints.ai_family != AF_INET)
  50. error(EAI_ADDRFAMILY);
  51. if (sptr->family != AF_INET)
  52. continue; /* ignore */
  53. rc = ga_aistruct(&aipnext, &hints, &inaddr, AF_INET);
  54. if (rc != 0)
  55. error(rc);
  56. continue;
  57. }
  58. }
  59. #endif
  60. #ifdef IPv6
  61. /* 4check for an IPv6 hex string */
  62. if ((isxdigit(sptr->host[0]) || sptr->host[0] == ':') &&
  63. (strchr(sptr->host, ':') != NULL)) {
  64. struct in6_addr in6addr;
  65. if (inet_pton(AF_INET6, sptr->host, &in6addr) == 1) {
  66. if (hints.ai_family != AF_UNSPEC &&
  67. hints.ai_family != AF_INET6)
  68. error(EAI_ADDRFAMILY);
  69. if (sptr->family != AF_INET6)
  70. continue; /* ignore */
  71. rc = ga_aistruct(&aipnext, &hints, &in6addr, AF_INET6);
  72. if (rc != 0)
  73. error(rc);
  74. continue;
  75. }
  76. }
  77. #endif
  78. /* end ga3 */
  79. /* include ga4 */
  80. /* 4remainder of for() to look up hostname */
  81. if ((_res.options & RES_INIT) == 0)
  82. res_init(); /* need this to set _res.options */
  83. if (nsearch == 2) {
  84. #ifdef IPv6
  85. _res.options &= ~RES_USE_INET6;
  86. #endif
  87. hptr = gethostbyname2(sptr->host, sptr->family);
  88. } else {
  89. #ifdef IPv6
  90. if (sptr->family == AF_INET6)
  91. _res.options |= RES_USE_INET6;
  92. else
  93. _res.options &= ~RES_USE_INET6;
  94. #endif
  95. hptr = gethostbyname(sptr->host);
  96. }
  97. if (hptr == NULL) {
  98. if (nsearch == 2)
  99. continue; /* failure OK if multiple searches */
  100. switch (h_errno) {
  101. case HOST_NOT_FOUND: error(EAI_NONAME);
  102. case TRY_AGAIN: error(EAI_AGAIN);
  103. case NO_RECOVERY: error(EAI_FAIL);
  104. case NO_DATA: error(EAI_NODATA);
  105. default: error(EAI_NONAME);
  106. }
  107. }
  108. /* 4check for address family mismatch if one specified */
  109. if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
  110. error(EAI_ADDRFAMILY);
  111. /* 4save canonical name first time */
  112. if (hostname != NULL && hostname[0] != '\0' &&
  113. (hints.ai_flags & AI_CANONNAME) && canon == NULL) {
  114. if ( (canon = strdup(hptr->h_name)) == NULL)
  115. error(EAI_MEMORY);
  116. }
  117. /* 4create one addrinfo{} for each returned address */
  118. for (ap = hptr->h_addr_list; *ap != NULL; ap++) {
  119. rc = ga_aistruct(&aipnext, &hints, *ap, hptr->h_addrtype);
  120. if (rc != 0)
  121. error(rc);
  122. }
  123. }
  124. if (aihead == NULL)
  125. error(EAI_NONAME); /* nothing found */
  126. /* end ga4 */
  127. /* include ga5 */
  128. /* 4return canonical name */
  129. if (hostname != NULL && hostname[0] != '\0' &&
  130. hints.ai_flags & AI_CANONNAME) {
  131. if (canon != NULL)
  132. aihead->ai_canonname = canon; /* strdup'ed earlier */
  133. else {
  134. if ( (aihead->ai_canonname = strdup(search[0].host)) == NULL)
  135. error(EAI_MEMORY);
  136. }
  137. }
  138. /* 4now process the service name */
  139. if (servname != NULL && servname[0] != '\0') {
  140. if ( (rc = ga_serv(aihead, &hints, servname)) != 0)
  141. error(rc);
  142. }
  143. *result = aihead; /* pointer to first structure in linked list */
  144. return(0);
  145. bad:
  146. freeaddrinfo(aihead); /* free any alloc'ed memory */
  147. return(error);
  148. }
  149. /* end ga5 */