run-16-duplex-test.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /* Tests when the last connection is a duplex, and poll.c moves it over
  2. * deleted fd. */
  3. #include <ccan/io/io.h>
  4. /* Include the C files directly. */
  5. #include <ccan/io/poll.c>
  6. #include <ccan/io/io.c>
  7. #include <ccan/tap/tap.h>
  8. #include <sys/wait.h>
  9. #include <stdio.h>
  10. #ifndef PORT
  11. #define PORT "65016"
  12. #endif
  13. struct data {
  14. struct io_listener *l;
  15. int state;
  16. char buf[4];
  17. char wbuf[32];
  18. };
  19. static void finish_ok(struct io_conn *conn, struct data *d)
  20. {
  21. d->state++;
  22. }
  23. static struct io_plan *io_done(struct io_conn *conn, struct data *d)
  24. {
  25. d->state++;
  26. if (d->state == 3)
  27. return io_close(conn);
  28. return io_wait(conn, d, io_close_cb, NULL);
  29. }
  30. static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
  31. {
  32. ok1(d->state == 0);
  33. d->state++;
  34. memset(d->wbuf, 7, sizeof(d->wbuf));
  35. io_set_finish(conn, finish_ok, d);
  36. io_close_listener(d->l);
  37. return io_duplex(io_read(conn, d->buf, sizeof(d->buf), io_done, d),
  38. io_write(conn, d->wbuf, sizeof(d->wbuf), io_done, d));
  39. }
  40. static int make_listen_fd(const char *port, struct addrinfo **info)
  41. {
  42. int fd, on = 1;
  43. struct addrinfo *addrinfo, hints;
  44. memset(&hints, 0, sizeof(hints));
  45. hints.ai_family = AF_UNSPEC;
  46. hints.ai_socktype = SOCK_STREAM;
  47. hints.ai_flags = AI_PASSIVE;
  48. hints.ai_protocol = 0;
  49. if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
  50. return -1;
  51. fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
  52. addrinfo->ai_protocol);
  53. if (fd < 0)
  54. return -1;
  55. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  56. if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
  57. close(fd);
  58. return -1;
  59. }
  60. if (listen(fd, 1) != 0) {
  61. close(fd);
  62. return -1;
  63. }
  64. *info = addrinfo;
  65. return fd;
  66. }
  67. int main(void)
  68. {
  69. struct data *d = malloc(sizeof(*d));
  70. struct addrinfo *addrinfo;
  71. int fd, status;
  72. /* This is how many tests you plan to run */
  73. plan_tests(9);
  74. d->state = 0;
  75. fd = make_listen_fd(PORT, &addrinfo);
  76. ok1(fd >= 0);
  77. d->l = io_new_listener(NULL, fd, init_conn, d);
  78. ok1(d->l);
  79. fflush(stdout);
  80. if (!fork()) {
  81. int i;
  82. char buf[32];
  83. io_close_listener(d->l);
  84. free(d);
  85. fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
  86. addrinfo->ai_protocol);
  87. if (fd < 0)
  88. exit(1);
  89. if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
  90. exit(2);
  91. signal(SIGPIPE, SIG_IGN);
  92. for (i = 0; i < 32; i++) {
  93. if (read(fd, buf+i, 1) != 1)
  94. break;
  95. }
  96. for (i = 0; i < strlen("hellothere"); i++) {
  97. if (write(fd, "hellothere" + i, 1) != 1)
  98. break;
  99. }
  100. close(fd);
  101. freeaddrinfo(addrinfo);
  102. exit(0);
  103. }
  104. freeaddrinfo(addrinfo);
  105. ok1(io_loop(NULL, NULL) == NULL);
  106. ok1(d->state == 4);
  107. ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
  108. free(d);
  109. ok1(wait(&status));
  110. ok1(WIFEXITED(status));
  111. ok1(WEXITSTATUS(status) == 0);
  112. /* This exits depending on whether all tests passed */
  113. return exit_status();
  114. }