netstuff.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* Operations on network stuff.
  2. Copyright (C) 2018-2022 Free Software Foundation, Inc.
  3. This file is part of GDB.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program 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
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include "common-defs.h"
  15. #include "netstuff.h"
  16. #include <algorithm>
  17. #ifdef USE_WIN32API
  18. #include <ws2tcpip.h>
  19. #else
  20. #include <netinet/in.h>
  21. #include <arpa/inet.h>
  22. #include <netdb.h>
  23. #include <sys/socket.h>
  24. #include <netinet/tcp.h>
  25. #endif
  26. /* See gdbsupport/netstuff.h. */
  27. scoped_free_addrinfo::~scoped_free_addrinfo ()
  28. {
  29. freeaddrinfo (m_res);
  30. }
  31. /* See gdbsupport/netstuff.h. */
  32. parsed_connection_spec
  33. parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
  34. {
  35. parsed_connection_spec ret;
  36. size_t last_colon_pos = 0;
  37. /* We're dealing with IPv6 if:
  38. - ai_family is AF_INET6, or
  39. - ai_family is not AF_INET, and
  40. - spec[0] is '[', or
  41. - the number of ':' on spec is greater than 1. */
  42. bool is_ipv6 = (hint->ai_family == AF_INET6
  43. || (hint->ai_family != AF_INET
  44. && (spec[0] == '['
  45. || std::count (spec.begin (),
  46. spec.end (), ':') > 1)));
  47. if (is_ipv6)
  48. {
  49. if (spec[0] == '[')
  50. {
  51. /* IPv6 addresses can be written as '[ADDR]:PORT', and we
  52. support this notation. */
  53. size_t close_bracket_pos = spec.find_first_of (']');
  54. if (close_bracket_pos == std::string::npos)
  55. error (_("Missing close bracket in hostname '%s'"),
  56. spec.c_str ());
  57. hint->ai_family = AF_INET6;
  58. const char c = spec[close_bracket_pos + 1];
  59. if (c == '\0')
  60. last_colon_pos = std::string::npos;
  61. else if (c != ':')
  62. error (_("Invalid cruft after close bracket in '%s'"),
  63. spec.c_str ());
  64. /* Erase both '[' and ']'. */
  65. spec.erase (0, 1);
  66. spec.erase (close_bracket_pos - 1, 1);
  67. }
  68. else if (spec.find_first_of (']') != std::string::npos)
  69. error (_("Missing open bracket in hostname '%s'"),
  70. spec.c_str ());
  71. }
  72. if (last_colon_pos == 0)
  73. last_colon_pos = spec.find_last_of (':');
  74. /* The length of the hostname part. */
  75. size_t host_len;
  76. if (last_colon_pos != std::string::npos)
  77. {
  78. /* The user has provided a port. */
  79. host_len = last_colon_pos;
  80. ret.port_str = spec.substr (last_colon_pos + 1);
  81. }
  82. else
  83. host_len = spec.size ();
  84. ret.host_str = spec.substr (0, host_len);
  85. /* Default hostname is localhost. */
  86. if (ret.host_str.empty ())
  87. ret.host_str = "localhost";
  88. return ret;
  89. }
  90. /* See gdbsupport/netstuff.h. */
  91. parsed_connection_spec
  92. parse_connection_spec (const char *spec, struct addrinfo *hint)
  93. {
  94. /* Struct to hold the association between valid prefixes, their
  95. family and socktype. */
  96. struct host_prefix
  97. {
  98. /* The prefix. */
  99. const char *prefix;
  100. /* The 'ai_family'. */
  101. int family;
  102. /* The 'ai_socktype'. */
  103. int socktype;
  104. };
  105. static const struct host_prefix prefixes[] =
  106. {
  107. { "udp:", AF_UNSPEC, SOCK_DGRAM },
  108. { "tcp:", AF_UNSPEC, SOCK_STREAM },
  109. { "udp4:", AF_INET, SOCK_DGRAM },
  110. { "tcp4:", AF_INET, SOCK_STREAM },
  111. { "udp6:", AF_INET6, SOCK_DGRAM },
  112. { "tcp6:", AF_INET6, SOCK_STREAM },
  113. };
  114. for (const host_prefix prefix : prefixes)
  115. if (startswith (spec, prefix.prefix))
  116. {
  117. spec += strlen (prefix.prefix);
  118. hint->ai_family = prefix.family;
  119. hint->ai_socktype = prefix.socktype;
  120. hint->ai_protocol
  121. = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
  122. break;
  123. }
  124. return parse_connection_spec_without_prefix (spec, hint);
  125. }