run-15-timeout.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include <ccan/io/io.h>
  2. /* Include the C files directly. */
  3. #include <ccan/io/poll.c>
  4. #include <ccan/io/io.c>
  5. #include <ccan/tap/tap.h>
  6. #include <ccan/time/time.h>
  7. #include <sys/wait.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #ifdef DEBUG_CONN
  11. #define PORT "64015"
  12. #else
  13. #define PORT "65015"
  14. #endif
  15. struct data {
  16. struct timers timers;
  17. int state;
  18. struct io_conn *conn;
  19. struct timer timer;
  20. int timeout_usec;
  21. char buf[4];
  22. };
  23. static void finish_ok(struct io_conn *conn, struct data *d)
  24. {
  25. d->state++;
  26. io_break(d);
  27. }
  28. static struct io_plan *no_timeout(struct io_conn *conn, struct data *d)
  29. {
  30. ok1(d->state == 1);
  31. d->state++;
  32. return io_close(conn);
  33. }
  34. static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
  35. {
  36. #ifdef DEBUG_CONN
  37. io_set_debug(conn, true);
  38. #endif
  39. ok1(d->state == 0);
  40. d->state++;
  41. d->conn = conn;
  42. io_set_finish(conn, finish_ok, d);
  43. timer_add(&d->timers, &d->timer,
  44. timeabs_add(time_now(), time_from_usec(d->timeout_usec)));
  45. return io_read(conn, d->buf, sizeof(d->buf), no_timeout, d);
  46. }
  47. static int make_listen_fd(const char *port, struct addrinfo **info)
  48. {
  49. int fd, on = 1;
  50. struct addrinfo *addrinfo, hints;
  51. memset(&hints, 0, sizeof(hints));
  52. hints.ai_family = AF_UNSPEC;
  53. hints.ai_socktype = SOCK_STREAM;
  54. hints.ai_flags = AI_PASSIVE;
  55. hints.ai_protocol = 0;
  56. if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
  57. return -1;
  58. fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
  59. addrinfo->ai_protocol);
  60. if (fd < 0)
  61. return -1;
  62. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  63. if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
  64. close(fd);
  65. return -1;
  66. }
  67. if (listen(fd, 1) != 0) {
  68. close(fd);
  69. return -1;
  70. }
  71. *info = addrinfo;
  72. return fd;
  73. }
  74. int main(void)
  75. {
  76. struct data *d = malloc(sizeof(*d));
  77. struct addrinfo *addrinfo;
  78. struct io_listener *l;
  79. struct timer *expired;
  80. int fd, status;
  81. /* This is how many tests you plan to run */
  82. plan_tests(21);
  83. d->state = 0;
  84. d->timeout_usec = 100000;
  85. timers_init(&d->timers, time_now());
  86. timer_init(&d->timer);
  87. fd = make_listen_fd(PORT, &addrinfo);
  88. ok1(fd >= 0);
  89. l = io_new_listener(NULL, fd, init_conn, d);
  90. ok1(l);
  91. fflush(stdout);
  92. if (!fork()) {
  93. int i;
  94. io_close_listener(l);
  95. fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
  96. addrinfo->ai_protocol);
  97. if (fd < 0)
  98. exit(1);
  99. if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
  100. exit(2);
  101. signal(SIGPIPE, SIG_IGN);
  102. usleep(500000);
  103. for (i = 0; i < strlen("hellothere"); i++) {
  104. if (write(fd, "hellothere" + i, 1) != 1)
  105. break;
  106. }
  107. close(fd);
  108. freeaddrinfo(addrinfo);
  109. timers_cleanup(&d->timers);
  110. free(d);
  111. exit(i);
  112. }
  113. ok1(io_loop(&d->timers, &expired) == NULL);
  114. /* One element, d->timer. */
  115. ok1(expired == &d->timer);
  116. ok1(!timers_expire(&d->timers, time_now()));
  117. ok1(d->state == 1);
  118. io_close(d->conn);
  119. /* Finished will be called, d will be returned */
  120. ok1(io_loop(&d->timers, &expired) == d);
  121. ok1(expired == NULL);
  122. ok1(d->state == 2);
  123. /* It should have died. */
  124. ok1(wait(&status));
  125. ok1(WIFEXITED(status));
  126. ok1(WEXITSTATUS(status) < sizeof(d->buf));
  127. /* This one shouldn't time out. */
  128. d->state = 0;
  129. d->timeout_usec = 500000;
  130. fflush(stdout);
  131. if (!fork()) {
  132. int i;
  133. io_close_listener(l);
  134. fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
  135. addrinfo->ai_protocol);
  136. if (fd < 0)
  137. exit(1);
  138. if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
  139. exit(2);
  140. signal(SIGPIPE, SIG_IGN);
  141. usleep(100000);
  142. for (i = 0; i < strlen("hellothere"); i++) {
  143. if (write(fd, "hellothere" + i, 1) != 1)
  144. break;
  145. }
  146. close(fd);
  147. freeaddrinfo(addrinfo);
  148. timers_cleanup(&d->timers);
  149. free(d);
  150. exit(i);
  151. }
  152. ok1(io_loop(&d->timers, &expired) == d);
  153. ok1(d->state == 3);
  154. ok1(expired == NULL);
  155. ok1(wait(&status));
  156. ok1(WIFEXITED(status));
  157. ok1(WEXITSTATUS(status) >= sizeof(d->buf));
  158. io_close_listener(l);
  159. freeaddrinfo(addrinfo);
  160. timers_cleanup(&d->timers);
  161. free(d);
  162. /* This exits depending on whether all tests passed */
  163. return exit_status();
  164. }