test-tcp-close-reset.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* Copyright libuv project contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "uv.h"
  22. #include "task.h"
  23. #include <errno.h>
  24. #include <string.h> /* memset */
  25. static uv_loop_t* loop;
  26. static uv_tcp_t tcp_server;
  27. static uv_tcp_t tcp_client;
  28. static uv_tcp_t tcp_accepted;
  29. static uv_connect_t connect_req;
  30. static uv_shutdown_t shutdown_req;
  31. static uv_write_t write_reqs[4];
  32. static int client_close;
  33. static int shutdown_before_close;
  34. static int write_cb_called;
  35. static int close_cb_called;
  36. static int shutdown_cb_called;
  37. static void connect_cb(uv_connect_t* req, int status);
  38. static void write_cb(uv_write_t* req, int status);
  39. static void close_cb(uv_handle_t* handle);
  40. static void shutdown_cb(uv_shutdown_t* req, int status);
  41. static int read_size;
  42. static void do_write(uv_tcp_t* handle) {
  43. uv_buf_t buf;
  44. unsigned i;
  45. int r;
  46. buf = uv_buf_init("PING", 4);
  47. for (i = 0; i < ARRAY_SIZE(write_reqs); i++) {
  48. r = uv_write(&write_reqs[i], (uv_stream_t*) handle, &buf, 1, write_cb);
  49. ASSERT(r == 0);
  50. }
  51. }
  52. static void do_close(uv_tcp_t* handle) {
  53. if (shutdown_before_close == 1) {
  54. ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb));
  55. ASSERT(UV_EINVAL == uv_tcp_close_reset(handle, close_cb));
  56. } else {
  57. ASSERT(0 == uv_tcp_close_reset(handle, close_cb));
  58. ASSERT(UV_ENOTCONN == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb));
  59. }
  60. uv_close((uv_handle_t*) &tcp_server, NULL);
  61. }
  62. static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
  63. static char slab[1024];
  64. buf->base = slab;
  65. buf->len = sizeof(slab);
  66. }
  67. static void read_cb2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
  68. ASSERT((uv_tcp_t*)stream == &tcp_client);
  69. if (nread == UV_EOF)
  70. uv_close((uv_handle_t*) stream, NULL);
  71. }
  72. static void connect_cb(uv_connect_t* conn_req, int status) {
  73. ASSERT(conn_req == &connect_req);
  74. uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb2);
  75. do_write(&tcp_client);
  76. if (client_close)
  77. do_close(&tcp_client);
  78. }
  79. static void write_cb(uv_write_t* req, int status) {
  80. /* write callbacks should run before the close callback */
  81. ASSERT(close_cb_called == 0);
  82. ASSERT(req->handle == (uv_stream_t*)&tcp_client);
  83. write_cb_called++;
  84. }
  85. static void close_cb(uv_handle_t* handle) {
  86. if (client_close)
  87. ASSERT(handle == (uv_handle_t*) &tcp_client);
  88. else
  89. ASSERT(handle == (uv_handle_t*) &tcp_accepted);
  90. close_cb_called++;
  91. }
  92. static void shutdown_cb(uv_shutdown_t* req, int status) {
  93. if (client_close)
  94. ASSERT(req->handle == (uv_stream_t*) &tcp_client);
  95. else
  96. ASSERT(req->handle == (uv_stream_t*) &tcp_accepted);
  97. shutdown_cb_called++;
  98. }
  99. static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
  100. ASSERT((uv_tcp_t*)stream == &tcp_accepted);
  101. if (nread < 0) {
  102. uv_close((uv_handle_t*) stream, NULL);
  103. } else {
  104. read_size += nread;
  105. if (read_size == 16 && client_close == 0)
  106. do_close(&tcp_accepted);
  107. }
  108. }
  109. static void connection_cb(uv_stream_t* server, int status) {
  110. ASSERT(status == 0);
  111. ASSERT(0 == uv_tcp_init(loop, &tcp_accepted));
  112. ASSERT(0 == uv_accept(server, (uv_stream_t*) &tcp_accepted));
  113. uv_read_start((uv_stream_t*) &tcp_accepted, alloc_cb, read_cb);
  114. }
  115. static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
  116. struct sockaddr_in addr;
  117. int r;
  118. ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
  119. r = uv_tcp_init(loop, handle);
  120. ASSERT(r == 0);
  121. r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
  122. ASSERT(r == 0);
  123. r = uv_listen((uv_stream_t*)handle, 128, connection_cb);
  124. ASSERT(r == 0);
  125. }
  126. static void do_connect(uv_loop_t* loop, uv_tcp_t* tcp_client) {
  127. struct sockaddr_in addr;
  128. int r;
  129. ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
  130. r = uv_tcp_init(loop, tcp_client);
  131. ASSERT(r == 0);
  132. r = uv_tcp_connect(&connect_req,
  133. tcp_client,
  134. (const struct sockaddr*) &addr,
  135. connect_cb);
  136. ASSERT(r == 0);
  137. }
  138. /* Check that pending write requests have their callbacks
  139. * invoked when the handle is closed.
  140. */
  141. TEST_IMPL(tcp_close_reset_client) {
  142. int r;
  143. loop = uv_default_loop();
  144. start_server(loop, &tcp_server);
  145. client_close = 1;
  146. shutdown_before_close = 0;
  147. do_connect(loop, &tcp_client);
  148. ASSERT(write_cb_called == 0);
  149. ASSERT(close_cb_called == 0);
  150. ASSERT(shutdown_cb_called == 0);
  151. r = uv_run(loop, UV_RUN_DEFAULT);
  152. ASSERT(r == 0);
  153. ASSERT(write_cb_called == 4);
  154. ASSERT(close_cb_called == 1);
  155. ASSERT(shutdown_cb_called == 0);
  156. MAKE_VALGRIND_HAPPY();
  157. return 0;
  158. }
  159. TEST_IMPL(tcp_close_reset_client_after_shutdown) {
  160. int r;
  161. loop = uv_default_loop();
  162. start_server(loop, &tcp_server);
  163. client_close = 1;
  164. shutdown_before_close = 1;
  165. do_connect(loop, &tcp_client);
  166. ASSERT(write_cb_called == 0);
  167. ASSERT(close_cb_called == 0);
  168. ASSERT(shutdown_cb_called == 0);
  169. r = uv_run(loop, UV_RUN_DEFAULT);
  170. ASSERT(r == 0);
  171. ASSERT(write_cb_called == 4);
  172. ASSERT(close_cb_called == 0);
  173. ASSERT(shutdown_cb_called == 1);
  174. MAKE_VALGRIND_HAPPY();
  175. return 0;
  176. }
  177. TEST_IMPL(tcp_close_reset_accepted) {
  178. int r;
  179. loop = uv_default_loop();
  180. start_server(loop, &tcp_server);
  181. client_close = 0;
  182. shutdown_before_close = 0;
  183. do_connect(loop, &tcp_client);
  184. ASSERT(write_cb_called == 0);
  185. ASSERT(close_cb_called == 0);
  186. ASSERT(shutdown_cb_called == 0);
  187. r = uv_run(loop, UV_RUN_DEFAULT);
  188. ASSERT(r == 0);
  189. ASSERT(write_cb_called == 4);
  190. ASSERT(close_cb_called == 1);
  191. ASSERT(shutdown_cb_called == 0);
  192. MAKE_VALGRIND_HAPPY();
  193. return 0;
  194. }
  195. TEST_IMPL(tcp_close_reset_accepted_after_shutdown) {
  196. int r;
  197. loop = uv_default_loop();
  198. start_server(loop, &tcp_server);
  199. client_close = 0;
  200. shutdown_before_close = 1;
  201. do_connect(loop, &tcp_client);
  202. ASSERT(write_cb_called == 0);
  203. ASSERT(close_cb_called == 0);
  204. ASSERT(shutdown_cb_called == 0);
  205. r = uv_run(loop, UV_RUN_DEFAULT);
  206. ASSERT(r == 0);
  207. ASSERT(write_cb_called == 4);
  208. ASSERT(close_cb_called == 0);
  209. ASSERT(shutdown_cb_called == 1);
  210. MAKE_VALGRIND_HAPPY();
  211. return 0;
  212. }