PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/support/support_format_addrinfo.c

https://gitlab.com/ultr/glibc
C | 202 lines | 163 code | 15 blank | 24 comment | 23 complexity | 48962fd5c63cef6ecbcea632b15e4528 MD5 | raw file
  1. /* Convert struct addrinfo values to a string.
  2. Copyright (C) 2016-2017 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <support/format_nss.h>
  16. #include <arpa/inet.h>
  17. #include <errno.h>
  18. #include <stdio.h>
  19. #include <support/support.h>
  20. #include <support/xmemstream.h>
  21. static size_t
  22. socket_address_length (int family)
  23. {
  24. switch (family)
  25. {
  26. case AF_INET:
  27. return sizeof (struct sockaddr_in);
  28. case AF_INET6:
  29. return sizeof (struct sockaddr_in6);
  30. default:
  31. return -1;
  32. }
  33. }
  34. static void
  35. format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
  36. int * flags_printed)
  37. {
  38. if ((ai->ai_flags & flag) != 0)
  39. fprintf (out, " %s", name);
  40. *flags_printed |= flag;
  41. }
  42. static void
  43. format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
  44. {
  45. /* ai_flags */
  46. if (ai->ai_flags != *flags)
  47. {
  48. fprintf (out, "flags:");
  49. int flags_printed = 0;
  50. #define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed)
  51. FLAG (AI_PASSIVE);
  52. FLAG (AI_CANONNAME);
  53. FLAG (AI_NUMERICHOST);
  54. FLAG (AI_V4MAPPED);
  55. FLAG (AI_ALL);
  56. FLAG (AI_ADDRCONFIG);
  57. FLAG (AI_IDN);
  58. FLAG (AI_CANONIDN);
  59. FLAG (AI_IDN_ALLOW_UNASSIGNED);
  60. FLAG (AI_IDN_USE_STD3_ASCII_RULES);
  61. FLAG (AI_NUMERICSERV);
  62. #undef FLAG
  63. int remaining = ai->ai_flags & ~flags_printed;
  64. if (remaining != 0)
  65. fprintf (out, " %08x", remaining);
  66. fprintf (out, "\n");
  67. *flags = ai->ai_flags;
  68. }
  69. {
  70. char type_buf[32];
  71. const char *type_str;
  72. char proto_buf[32];
  73. const char *proto_str;
  74. /* ai_socktype */
  75. switch (ai->ai_socktype)
  76. {
  77. case SOCK_RAW:
  78. type_str = "RAW";
  79. break;
  80. case SOCK_DGRAM:
  81. type_str = "DGRAM";
  82. break;
  83. case SOCK_STREAM:
  84. type_str = "STREAM";
  85. break;
  86. default:
  87. snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
  88. type_str = type_buf;
  89. }
  90. /* ai_protocol */
  91. switch (ai->ai_protocol)
  92. {
  93. case IPPROTO_IP:
  94. proto_str = "IP";
  95. break;
  96. case IPPROTO_UDP:
  97. proto_str = "UDP";
  98. break;
  99. case IPPROTO_TCP:
  100. proto_str = "TCP";
  101. break;
  102. default:
  103. snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
  104. proto_str = proto_buf;
  105. }
  106. fprintf (out, "address: %s/%s", type_str, proto_str);
  107. }
  108. /* ai_addrlen */
  109. if (ai->ai_addrlen != socket_address_length (ai->ai_family))
  110. {
  111. char *family = support_format_address_family (ai->ai_family);
  112. fprintf (out, "error: invalid address length %d for %s\n",
  113. ai->ai_addrlen, family);
  114. free (family);
  115. }
  116. /* ai_addr */
  117. {
  118. char buf[128];
  119. uint16_t port;
  120. const char *ret;
  121. switch (ai->ai_family)
  122. {
  123. case AF_INET:
  124. {
  125. struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
  126. ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
  127. port = sin->sin_port;
  128. }
  129. break;
  130. case AF_INET6:
  131. {
  132. struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
  133. ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
  134. port = sin->sin6_port;
  135. }
  136. break;
  137. default:
  138. errno = EAFNOSUPPORT;
  139. ret = NULL;
  140. }
  141. if (ret == NULL)
  142. fprintf (out, "error: inet_top failed: %m\n");
  143. else
  144. fprintf (out, " %s %u\n", buf, ntohs (port));
  145. }
  146. /* ai_canonname */
  147. if (ai->ai_canonname != NULL)
  148. fprintf (out, "canonname: %s\n", ai->ai_canonname);
  149. }
  150. /* Format all the addresses in one address family. */
  151. static void
  152. format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags)
  153. {
  154. while (ai)
  155. {
  156. if (ai->ai_family == family)
  157. format_ai_one (out, ai, flags);
  158. ai = ai->ai_next;
  159. }
  160. }
  161. char *
  162. support_format_addrinfo (struct addrinfo *ai, int ret)
  163. {
  164. int errno_copy = errno;
  165. struct xmemstream mem;
  166. xopen_memstream (&mem);
  167. if (ret != 0)
  168. {
  169. fprintf (mem.out, "error: %s\n", gai_strerror (ret));
  170. if (ret == EAI_SYSTEM)
  171. {
  172. errno = errno_copy;
  173. fprintf (mem.out, "error: %m\n");
  174. }
  175. }
  176. else
  177. {
  178. int flags = 0;
  179. format_ai_family (mem.out, ai, AF_INET, &flags);
  180. format_ai_family (mem.out, ai, AF_INET6, &flags);
  181. }
  182. xfclose_memstream (&mem);
  183. return mem.buffer;
  184. }