socket-helpers.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Helper functions for tests using sockets
  3. *
  4. * Copyright 2015-2018 Red Hat, Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 or
  9. * (at your option) version 3 of the License.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qemu/sockets.h"
  22. #include "socket-helpers.h"
  23. #ifndef AI_ADDRCONFIG
  24. # define AI_ADDRCONFIG 0
  25. #endif
  26. #ifndef EAI_ADDRFAMILY
  27. # define EAI_ADDRFAMILY 0
  28. #endif
  29. /*
  30. * @hostname: a DNS name or numeric IP address
  31. *
  32. * Check whether it is possible to bind & connect to ports
  33. * on the DNS name or IP address @hostname. If an IP address
  34. * is used, it must not be a wildcard address.
  35. *
  36. * Returns 0 on success, -1 on error with errno set
  37. */
  38. static int socket_can_bind_connect(const char *hostname, int family)
  39. {
  40. int lfd = -1, cfd = -1, afd = -1;
  41. struct addrinfo ai, *res = NULL;
  42. struct sockaddr_storage ss;
  43. socklen_t sslen = sizeof(ss);
  44. int soerr;
  45. socklen_t soerrlen = sizeof(soerr);
  46. bool check_soerr = false;
  47. int rc;
  48. int ret = -1;
  49. memset(&ai, 0, sizeof(ai));
  50. ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
  51. ai.ai_family = family;
  52. ai.ai_socktype = SOCK_STREAM;
  53. /* lookup */
  54. rc = getaddrinfo(hostname, NULL, &ai, &res);
  55. if (rc != 0) {
  56. if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) {
  57. errno = EADDRNOTAVAIL;
  58. } else {
  59. errno = EINVAL;
  60. }
  61. goto cleanup;
  62. }
  63. lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  64. if (lfd < 0) {
  65. goto cleanup;
  66. }
  67. cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  68. if (cfd < 0) {
  69. goto cleanup;
  70. }
  71. if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) {
  72. goto cleanup;
  73. }
  74. if (listen(lfd, 1) < 0) {
  75. goto cleanup;
  76. }
  77. if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) {
  78. goto cleanup;
  79. }
  80. qemu_socket_set_nonblock(cfd);
  81. if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
  82. if (errno == EINPROGRESS) {
  83. check_soerr = true;
  84. } else {
  85. goto cleanup;
  86. }
  87. }
  88. sslen = sizeof(ss);
  89. afd = accept(lfd, (struct sockaddr *)&ss, &sslen);
  90. if (afd < 0) {
  91. goto cleanup;
  92. }
  93. if (check_soerr) {
  94. if (getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) {
  95. goto cleanup;
  96. }
  97. if (soerr) {
  98. errno = soerr;
  99. goto cleanup;
  100. }
  101. }
  102. ret = 0;
  103. cleanup:
  104. if (afd != -1) {
  105. close(afd);
  106. }
  107. if (cfd != -1) {
  108. close(cfd);
  109. }
  110. if (lfd != -1) {
  111. close(lfd);
  112. }
  113. if (res) {
  114. freeaddrinfo(res);
  115. }
  116. return ret;
  117. }
  118. int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
  119. {
  120. *has_ipv4 = *has_ipv6 = false;
  121. if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
  122. if (errno != EADDRNOTAVAIL) {
  123. return -1;
  124. }
  125. } else {
  126. *has_ipv4 = true;
  127. }
  128. if (socket_can_bind_connect("::1", PF_INET6) < 0) {
  129. if (errno != EADDRNOTAVAIL) {
  130. return -1;
  131. }
  132. } else {
  133. *has_ipv6 = true;
  134. }
  135. return 0;
  136. }
  137. void socket_check_afunix_support(bool *has_afunix)
  138. {
  139. int fd;
  140. fd = socket(PF_UNIX, SOCK_STREAM, 0);
  141. close(fd);
  142. #ifdef _WIN32
  143. *has_afunix = (fd != (int)INVALID_SOCKET);
  144. #else
  145. *has_afunix = (fd >= 0);
  146. #endif
  147. return;
  148. }