run.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include <ccan/net/net.h>
  2. #include <ccan/net/net.c>
  3. #include <ccan/tap/tap.h>
  4. #include <sys/types.h>
  5. #include <sys/wait.h>
  6. #include <stdio.h>
  7. #include <err.h>
  8. static int server(int protocol, int type)
  9. {
  10. int sock;
  11. union {
  12. struct sockaddr addr;
  13. struct sockaddr_in ipv4;
  14. struct sockaddr_in6 ipv6;
  15. } addr;
  16. socklen_t addlen = sizeof(addr);
  17. sock = socket(protocol, type, 0);
  18. if (sock < 0)
  19. return -1;
  20. /* Bind to free port. */
  21. if (listen(sock, 0) != 0)
  22. return -1;
  23. /* Figure out what port it gave us. */
  24. getsockname(sock, &addr.addr, &addlen);
  25. fflush(stdout);
  26. if (fork() == 0) {
  27. int ret, fd;
  28. alarm(3);
  29. fd = accept(sock, NULL, 0);
  30. if (fd < 0)
  31. err(1, "Accepting from socket %i", sock);
  32. ret = write(fd, "Yay!", strlen("Yay!"));
  33. if (ret != strlen("Yay!"))
  34. err(1, "Write returned %i", ret);
  35. exit(0);
  36. }
  37. close(sock);
  38. return ntohs(protocol == AF_INET
  39. ? addr.ipv4.sin_port : addr.ipv6.sin6_port);
  40. }
  41. /* Get a localhost on ipv4 and IPv6. Fake it if we can. */
  42. static struct addrinfo* double_addr_lookup(char* buf, bool *fake_double)
  43. {
  44. struct addrinfo *addr, *addr2;
  45. addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
  46. if (!addr)
  47. return addr;
  48. /* If we only got one, we need to fake up the other one. */
  49. if (addr->ai_next) {
  50. addr2 = addr->ai_next;
  51. *fake_double = false;
  52. } else {
  53. /* OK, IPv4 only? */
  54. if (addr->ai_family == AF_INET) {
  55. /* These are the names I found on my Ubuntu system. */
  56. addr2 = net_client_lookup("ip6-localhost", buf,
  57. AF_UNSPEC, SOCK_STREAM);
  58. if (!addr2)
  59. addr2 = net_client_lookup("localhost6", buf,
  60. AF_UNSPEC,
  61. SOCK_STREAM);
  62. if (!addr2)
  63. addr2 = net_client_lookup("::1", buf,
  64. AF_UNSPEC,
  65. SOCK_STREAM);
  66. } else if (addr->ai_family == AF_INET6)
  67. /* IPv6 only? This is a guess... */
  68. addr2 = net_client_lookup("ip4-localhost", buf,
  69. AF_UNSPEC, SOCK_STREAM);
  70. /* Perhaps no support on this system? Go ahead with one. */
  71. if (!addr2) {
  72. *fake_double = false;
  73. return addr;
  74. }
  75. *fake_double = true;
  76. addr->ai_next = addr2;
  77. }
  78. /* More than two? */
  79. if (addr2->ai_next)
  80. return NULL;
  81. /* One IPv4 and one IPv6? */
  82. if (addr->ai_family == AF_INET && addr2->ai_family == AF_INET6)
  83. return addr;
  84. if (addr->ai_family == AF_INET6 && addr2->ai_family == AF_INET)
  85. return addr;
  86. return NULL;
  87. }
  88. static void double_addr_free(struct addrinfo* addr, bool fake_double)
  89. {
  90. if (fake_double) {
  91. freeaddrinfo(addr->ai_next);
  92. addr->ai_next = NULL;
  93. }
  94. freeaddrinfo(addr);
  95. }
  96. int main(void)
  97. {
  98. struct addrinfo *addr;
  99. int fd, status;
  100. struct sockaddr saddr;
  101. socklen_t slen;
  102. char buf[20];
  103. int port;
  104. bool fake_double;
  105. plan_tests(14);
  106. port = server(AF_INET, SOCK_STREAM);
  107. if (port == -1) {
  108. /* No IPv4 support? Maybe one day this will happen! */
  109. if (errno == EAFNOSUPPORT)
  110. skip(6, "No IPv4 socket support");
  111. else
  112. fail("Could not create IPv4 listening socket: %s",
  113. strerror(errno));
  114. } else {
  115. sprintf(buf, "%u", port);
  116. addr = double_addr_lookup(buf, &fake_double);
  117. ok1(addr);
  118. fd = net_connect(addr);
  119. ok1(fd >= 0);
  120. slen = sizeof(saddr);
  121. ok1(getsockname(fd, &saddr, &slen) == 0);
  122. diag("family = %d", saddr.sa_family);
  123. ok1(saddr.sa_family == AF_INET);
  124. status = read(fd, buf, sizeof(buf));
  125. ok(status == strlen("Yay!"),
  126. "Read returned %i (%s)", status, strerror(errno));
  127. ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
  128. close(fd);
  129. double_addr_free(addr, fake_double);
  130. }
  131. port = server(AF_INET6, SOCK_STREAM);
  132. if (port == -1) {
  133. /* No IPv6 support? */
  134. if (errno == EAFNOSUPPORT)
  135. skip(6, "No IPv6 socket support");
  136. else
  137. fail("Could not create IPv6 listening socket: %s",
  138. strerror(errno));
  139. } else {
  140. sprintf(buf, "%u", port);
  141. addr = double_addr_lookup(buf, &fake_double);
  142. ok1(addr);
  143. fd = net_connect(addr);
  144. ok1(fd >= 0);
  145. slen = sizeof(saddr);
  146. ok1(getsockname(fd, &saddr, &slen) == 0);
  147. ok1(saddr.sa_family == AF_INET6);
  148. status = read(fd, buf, sizeof(buf));
  149. ok(status == strlen("Yay!"),
  150. "Read returned %i (%s)", status, strerror(errno));
  151. ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
  152. close(fd);
  153. double_addr_free(addr, fake_double);
  154. }
  155. wait(&status);
  156. ok1(WIFEXITED(status));
  157. ok1(WEXITSTATUS(status) == 0);
  158. /* This exits depending on whether all tests passed */
  159. return exit_status();
  160. }