run-bind.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include <ccan/net/net.h>
  2. #include <ccan/tap/tap.h>
  3. #include <sys/time.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <stdio.h>
  8. #include <err.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. static int ipv6_only;
  13. #ifdef IPV6_V6ONLY
  14. static int my_setsockopt(int sockfd, int level, int optname,
  15. const void *optval, socklen_t optlen)
  16. {
  17. int ret;
  18. setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only,
  19. sizeof(ipv6_only));
  20. ret = setsockopt(sockfd, level, optname, optval, optlen);
  21. return ret;
  22. }
  23. #define setsockopt my_setsockopt
  24. #endif
  25. #include <ccan/net/net.c>
  26. #define TEST_PORT "65001"
  27. static void do_connect(int family, int type)
  28. {
  29. int fd, ret;
  30. struct addrinfo *addr;
  31. char buf[8];
  32. /* Just in case... */
  33. alarm(5);
  34. addr = net_client_lookup(NULL, TEST_PORT, family, type);
  35. fd = net_connect(addr);
  36. if (fd < 0)
  37. err(1, "Failed net_connect");
  38. freeaddrinfo(addr);
  39. ret = write(fd, "Yay!", strlen("Yay!"));
  40. if (ret != strlen("Yay!"))
  41. err(1, "Write returned %i", ret);
  42. ret = read(fd, buf, sizeof(buf));
  43. if (ret != 5)
  44. err(1, "Read returned %i", ret);
  45. if (memcmp(buf, "metoo", ret) != 0)
  46. err(1, "Read returned '%.*s'", ret, buf);
  47. close(fd);
  48. }
  49. static int wait_for_readable(int fds[2], int num_fds)
  50. {
  51. int i, max_fd = -1;
  52. fd_set set;
  53. FD_ZERO(&set);
  54. for (i = 0; i < num_fds; i++) {
  55. if (fds[i] > max_fd)
  56. max_fd = fds[i];
  57. FD_SET(fds[i], &set);
  58. }
  59. select(max_fd+1, &set, NULL, NULL, NULL);
  60. for (i = 0; i < num_fds; i++) {
  61. if (FD_ISSET(fds[i], &set))
  62. return i;
  63. }
  64. return num_fds+1;
  65. }
  66. int main(void)
  67. {
  68. struct addrinfo *addr;
  69. int fds[2], num_fds, i, fd, status, ret;
  70. char buf[20];
  71. union {
  72. struct sockaddr addr;
  73. struct sockaddr_in ipv4;
  74. struct sockaddr_in6 ipv6;
  75. } remote_addr;
  76. socklen_t addlen = sizeof(remote_addr);
  77. plan_tests(35);
  78. /* Simple TCP test. */
  79. addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_STREAM);
  80. ok1(addr);
  81. num_fds = net_bind(addr, fds);
  82. ok1(num_fds == 1 || num_fds == 2);
  83. if (!fork()) {
  84. for (i = 0; i < num_fds; i++)
  85. close(fds[i]);
  86. do_connect(AF_UNSPEC, SOCK_STREAM);
  87. exit(0);
  88. }
  89. i = wait_for_readable(fds, num_fds);
  90. ok1(i < num_fds);
  91. fd = accept(fds[i], NULL, NULL);
  92. ok1(fd >= 0);
  93. ret = read(fd, buf, strlen("Yay!"));
  94. ok1(ret == strlen("Yay!"));
  95. ok1(memcmp(buf, "Yay!", ret) == 0);
  96. ret = write(fd, "metoo", strlen("metoo"));
  97. ok1(ret == strlen("metoo"));
  98. ok1(wait(&status) != -1);
  99. ok1(WIFEXITED(status));
  100. ok1(WEXITSTATUS(status) == 0);
  101. close(fd);
  102. for (i = 0; i < num_fds; i++)
  103. close(fds[i]);
  104. /* Simple UDP test. */
  105. addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_DGRAM);
  106. ok1(addr);
  107. num_fds = net_bind(addr, fds);
  108. ok1(num_fds == 1 || num_fds == 2);
  109. if (!fork()) {
  110. for (i = 0; i < num_fds; i++)
  111. close(fds[i]);
  112. do_connect(AF_UNSPEC, SOCK_DGRAM);
  113. exit(0);
  114. }
  115. i = wait_for_readable(fds, num_fds);
  116. ok1(i < num_fds);
  117. fd = fds[i];
  118. ret = recvfrom(fd, buf, strlen("Yay!"), 0,
  119. (void *)&remote_addr, &addlen);
  120. ok1(ret == strlen("Yay!"));
  121. ok1(memcmp(buf, "Yay!", ret) == 0);
  122. ret = sendto(fd, "metoo", strlen("metoo"), 0,
  123. (void *)&remote_addr, addlen);
  124. ok1(ret == strlen("metoo"));
  125. ok1(wait(&status) >= 0);
  126. ok1(WIFEXITED(status));
  127. ok1(WEXITSTATUS(status) == 0);
  128. close(fd);
  129. for (i = 0; i < num_fds; i++)
  130. close(fds[i]);
  131. /* This seems like a Linux-only extension */
  132. #ifdef IPV6_V6ONLY
  133. /* Try to force separate sockets for IPv4/IPv6, if we can. */
  134. if (addr->ai_next)
  135. ipv6_only = true;
  136. #endif
  137. if (ipv6_only) {
  138. int j;
  139. addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_STREAM);
  140. ok1(addr);
  141. num_fds = net_bind(addr, fds);
  142. ok1(num_fds == 2);
  143. freeaddrinfo(addr);
  144. if (!fork()) {
  145. for (i = 0; i < num_fds; i++)
  146. close(fds[i]);
  147. do_connect(AF_INET, SOCK_STREAM);
  148. do_connect(AF_INET6, SOCK_STREAM);
  149. exit(0);
  150. }
  151. i = wait_for_readable(fds, num_fds);
  152. ok1(i < num_fds);
  153. fd = accept(fds[i], NULL, NULL);
  154. ok1(fd >= 0);
  155. ret = read(fd, buf, strlen("Yay!"));
  156. ok1(ret == strlen("Yay!"));
  157. ok1(memcmp(buf, "Yay!", ret) == 0);
  158. ret = write(fd, "metoo", strlen("metoo"));
  159. ok1(ret == strlen("metoo"));
  160. close(fd);
  161. j = wait_for_readable(fds, num_fds);
  162. ok1(j < num_fds);
  163. ok1(j != i);
  164. fd = accept(fds[j], NULL, NULL);
  165. ok1(fd >= 0);
  166. ret = read(fd, buf, strlen("Yay!"));
  167. ok1(ret == strlen("Yay!"));
  168. ok1(memcmp(buf, "Yay!", ret) == 0);
  169. ret = write(fd, "metoo", strlen("metoo"));
  170. ok1(ret == strlen("metoo"));
  171. ok1(wait(&status) >= 0);
  172. ok1(WIFEXITED(status));
  173. ok1(WEXITSTATUS(status) == 0);
  174. close(fd);
  175. } else
  176. skip(16, "No support for IPv6-only binding");
  177. for (i = 0; i < num_fds; i++)
  178. close(fds[i]);
  179. /* This exits depending on whether all tests passed */
  180. return exit_status();
  181. }