1
0

gethostbyname2_r.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #define _GNU_SOURCE
  2. #include <sys/socket.h>
  3. #include <netdb.h>
  4. #include <string.h>
  5. #include <netinet/in.h>
  6. #include <errno.h>
  7. #include <stdint.h>
  8. int gethostbyname2_r(const char *name, int af,
  9. struct hostent *h, char *buf, size_t buflen,
  10. struct hostent **res, int *err)
  11. {
  12. struct addrinfo hint = {
  13. .ai_family = af==AF_INET6 ? af : AF_INET,
  14. .ai_flags = AI_CANONNAME
  15. };
  16. struct addrinfo *ai, *p;
  17. int i;
  18. size_t need;
  19. const char *canon;
  20. *res = 0;
  21. af = hint.ai_family;
  22. /* Align buffer */
  23. i = (uintptr_t)buf & sizeof(char *)-1;
  24. if (i) {
  25. if (buflen < sizeof(char *)-i) return ERANGE;
  26. buf += sizeof(char *)-i;
  27. buflen -= sizeof(char *)-i;
  28. }
  29. switch (getaddrinfo(name, 0, &hint, &ai)) {
  30. case EAI_NONAME:
  31. *err = HOST_NOT_FOUND;
  32. return errno;
  33. case EAI_AGAIN:
  34. *err = TRY_AGAIN;
  35. return errno;
  36. default:
  37. case EAI_MEMORY:
  38. case EAI_SYSTEM:
  39. case EAI_FAIL:
  40. *err = NO_RECOVERY;
  41. return errno;
  42. case 0:
  43. break;
  44. }
  45. h->h_addrtype = af;
  46. h->h_length = af==AF_INET6 ? 16 : 4;
  47. canon = ai->ai_canonname ? ai->ai_canonname : name;
  48. need = 4*sizeof(char *);
  49. for (i=0, p=ai; p; i++, p=p->ai_next)
  50. need += sizeof(char *) + h->h_length;
  51. need += strlen(name)+1;
  52. need += strlen(canon)+1;
  53. if (need > buflen) {
  54. freeaddrinfo(ai);
  55. return ERANGE;
  56. }
  57. h->h_aliases = (void *)buf;
  58. buf += 3*sizeof(char *);
  59. h->h_addr_list = (void *)buf;
  60. buf += (i+1)*sizeof(char *);
  61. h->h_name = h->h_aliases[0] = buf;
  62. strcpy(h->h_name, canon);
  63. buf += strlen(h->h_name)+1;
  64. if (strcmp(h->h_name, name)) {
  65. h->h_aliases[1] = buf;
  66. strcpy(h->h_aliases[1], name);
  67. buf += strlen(h->h_aliases[1])+1;
  68. } else h->h_aliases[1] = 0;
  69. h->h_aliases[2] = 0;
  70. for (i=0, p=ai; p; i++, p=p->ai_next) {
  71. h->h_addr_list[i] = (void *)buf;
  72. buf += h->h_length;
  73. memcpy(h->h_addr_list[i],
  74. &((struct sockaddr_in *)p->ai_addr)->sin_addr,
  75. h->h_length);
  76. }
  77. h->h_addr_list[i] = 0;
  78. *res = h;
  79. freeaddrinfo(ai);
  80. return 0;
  81. }