/Modules/getnameinfo.c

http://unladen-swallow.googlecode.com/ · C · 214 lines · 160 code · 17 blank · 37 comment · 51 complexity · a481b0b37139308e793d3fc79e87033b MD5 · raw file

  1. /*
  2. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the project nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * Issues to be discussed:
  31. * - Thread safe-ness must be checked
  32. * - Return values. There seems to be no standard for return value (RFC2133)
  33. * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
  34. */
  35. #if 0
  36. #include <sys/types.h>
  37. #include <sys/socket.h>
  38. #include <netinet/in.h>
  39. #include <arpa/inet.h>
  40. #include <arpa/nameser.h>
  41. #include <netdb.h>
  42. #include <resolv.h>
  43. #include <string.h>
  44. #include <stddef.h>
  45. #include "addrinfo.h"
  46. #endif
  47. #define SUCCESS 0
  48. #define YES 1
  49. #define NO 0
  50. static struct gni_afd {
  51. int a_af;
  52. int a_addrlen;
  53. int a_socklen;
  54. int a_off;
  55. } gni_afdl [] = {
  56. #ifdef ENABLE_IPV6
  57. {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
  58. offsetof(struct sockaddr_in6, sin6_addr)},
  59. #endif
  60. {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
  61. offsetof(struct sockaddr_in, sin_addr)},
  62. {0, 0, 0},
  63. };
  64. struct gni_sockinet {
  65. u_char si_len;
  66. u_char si_family;
  67. u_short si_port;
  68. };
  69. #define ENI_NOSOCKET 0
  70. #define ENI_NOSERVNAME 1
  71. #define ENI_NOHOSTNAME 2
  72. #define ENI_MEMORY 3
  73. #define ENI_SYSTEM 4
  74. #define ENI_FAMILY 5
  75. #define ENI_SALEN 6
  76. /* forward declaration to make gcc happy */
  77. int getnameinfo Py_PROTO((const struct sockaddr *, size_t, char *, size_t,
  78. char *, size_t, int));
  79. int
  80. getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
  81. const struct sockaddr *sa;
  82. size_t salen;
  83. char *host;
  84. size_t hostlen;
  85. char *serv;
  86. size_t servlen;
  87. int flags;
  88. {
  89. struct gni_afd *gni_afd;
  90. struct servent *sp;
  91. struct hostent *hp;
  92. u_short port;
  93. int family, len, i;
  94. char *addr, *p;
  95. u_long v4a;
  96. #ifdef ENABLE_IPV6
  97. u_char pfx;
  98. #endif
  99. int h_error;
  100. char numserv[512];
  101. char numaddr[512];
  102. if (sa == NULL)
  103. return ENI_NOSOCKET;
  104. #ifdef HAVE_SOCKADDR_SA_LEN
  105. len = sa->sa_len;
  106. if (len != salen) return ENI_SALEN;
  107. #else
  108. len = salen;
  109. #endif
  110. family = sa->sa_family;
  111. for (i = 0; gni_afdl[i].a_af; i++)
  112. if (gni_afdl[i].a_af == family) {
  113. gni_afd = &gni_afdl[i];
  114. goto found;
  115. }
  116. return ENI_FAMILY;
  117. found:
  118. if (len != gni_afd->a_socklen) return ENI_SALEN;
  119. port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
  120. addr = (char *)sa + gni_afd->a_off;
  121. if (serv == NULL || servlen == 0) {
  122. /* what we should do? */
  123. } else if (flags & NI_NUMERICSERV) {
  124. sprintf(numserv, "%d", ntohs(port));
  125. if (strlen(numserv) > servlen)
  126. return ENI_MEMORY;
  127. strcpy(serv, numserv);
  128. } else {
  129. sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
  130. if (sp) {
  131. if (strlen(sp->s_name) > servlen)
  132. return ENI_MEMORY;
  133. strcpy(serv, sp->s_name);
  134. } else
  135. return ENI_NOSERVNAME;
  136. }
  137. switch (sa->sa_family) {
  138. case AF_INET:
  139. v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
  140. if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
  141. flags |= NI_NUMERICHOST;
  142. v4a >>= IN_CLASSA_NSHIFT;
  143. if (v4a == 0 || v4a == IN_LOOPBACKNET)
  144. flags |= NI_NUMERICHOST;
  145. break;
  146. #ifdef ENABLE_IPV6
  147. case AF_INET6:
  148. pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
  149. if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
  150. flags |= NI_NUMERICHOST;
  151. break;
  152. #endif
  153. }
  154. if (host == NULL || hostlen == 0) {
  155. /* what should we do? */
  156. } else if (flags & NI_NUMERICHOST) {
  157. if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
  158. == NULL)
  159. return ENI_SYSTEM;
  160. if (strlen(numaddr) > hostlen)
  161. return ENI_MEMORY;
  162. strcpy(host, numaddr);
  163. } else {
  164. #ifdef ENABLE_IPV6
  165. hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
  166. #else
  167. hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af);
  168. h_error = h_errno;
  169. #endif
  170. if (hp) {
  171. if (flags & NI_NOFQDN) {
  172. p = strchr(hp->h_name, '.');
  173. if (p) *p = '\0';
  174. }
  175. if (strlen(hp->h_name) > hostlen) {
  176. #ifdef ENABLE_IPV6
  177. freehostent(hp);
  178. #endif
  179. return ENI_MEMORY;
  180. }
  181. strcpy(host, hp->h_name);
  182. #ifdef ENABLE_IPV6
  183. freehostent(hp);
  184. #endif
  185. } else {
  186. if (flags & NI_NAMEREQD)
  187. return ENI_NOHOSTNAME;
  188. if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
  189. == NULL)
  190. return ENI_NOHOSTNAME;
  191. if (strlen(numaddr) > hostlen)
  192. return ENI_MEMORY;
  193. strcpy(host, numaddr);
  194. }
  195. }
  196. return SUCCESS;
  197. }