xref: /libuv/test/test-tcp-close.c (revision 011a1ac1)
1 /* Copyright Joyent, Inc. and other Node 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 
22 #include "uv.h"
23 #include "task.h"
24 
25 #include <errno.h>
26 #include <string.h> /* memset */
27 
28 #define NUM_WRITE_REQS 32
29 
30 static uv_tcp_t tcp_handle;
31 static uv_connect_t connect_req;
32 
33 static int write_cb_called;
34 static int close_cb_called;
35 
36 static void connect_cb(uv_connect_t* req, int status);
37 static void write_cb(uv_write_t* req, int status);
38 static void close_cb(uv_handle_t* handle);
39 
40 
connect_cb(uv_connect_t * conn_req,int status)41 static void connect_cb(uv_connect_t* conn_req, int status) {
42   uv_write_t* req;
43   uv_buf_t buf;
44   int i, r;
45 
46   buf = uv_buf_init("PING", 4);
47   for (i = 0; i < NUM_WRITE_REQS; i++) {
48     req = malloc(sizeof *req);
49     ASSERT_NOT_NULL(req);
50 
51     r = uv_write(req, (uv_stream_t*)&tcp_handle, &buf, 1, write_cb);
52     ASSERT_OK(r);
53   }
54 
55   uv_close((uv_handle_t*)&tcp_handle, close_cb);
56 }
57 
58 
write_cb(uv_write_t * req,int status)59 static void write_cb(uv_write_t* req, int status) {
60   /* write callbacks should run before the close callback */
61   ASSERT_OK(close_cb_called);
62   ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_handle);
63   write_cb_called++;
64   free(req);
65 }
66 
67 
close_cb(uv_handle_t * handle)68 static void close_cb(uv_handle_t* handle) {
69   ASSERT_PTR_EQ(handle, (uv_handle_t*)&tcp_handle);
70   close_cb_called++;
71 }
72 
73 
connection_cb(uv_stream_t * server,int status)74 static void connection_cb(uv_stream_t* server, int status) {
75   ASSERT_OK(status);
76 }
77 
78 
start_server(uv_loop_t * loop,uv_tcp_t * handle)79 static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
80   struct sockaddr_in addr;
81   int r;
82 
83   ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
84 
85   r = uv_tcp_init(loop, handle);
86   ASSERT_OK(r);
87 
88   r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
89   ASSERT_OK(r);
90 
91   r = uv_listen((uv_stream_t*)handle, 128, connection_cb);
92   ASSERT_OK(r);
93 
94   uv_unref((uv_handle_t*)handle);
95 }
96 
97 
98 /* Check that pending write requests have their callbacks
99  * invoked when the handle is closed.
100  */
TEST_IMPL(tcp_close)101 TEST_IMPL(tcp_close) {
102   struct sockaddr_in addr;
103   uv_tcp_t tcp_server;
104   uv_loop_t* loop;
105   int r;
106 
107   ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
108 
109   loop = uv_default_loop();
110 
111   /* We can't use the echo server, it doesn't handle ECONNRESET. */
112   start_server(loop, &tcp_server);
113 
114   r = uv_tcp_init(loop, &tcp_handle);
115   ASSERT_OK(r);
116 
117   r = uv_tcp_connect(&connect_req,
118                      &tcp_handle,
119                      (const struct sockaddr*) &addr,
120                      connect_cb);
121   ASSERT_OK(r);
122 
123   ASSERT_OK(write_cb_called);
124   ASSERT_OK(close_cb_called);
125 
126   r = uv_run(loop, UV_RUN_DEFAULT);
127   ASSERT_OK(r);
128 
129   printf("%d of %d write reqs seen\n", write_cb_called, NUM_WRITE_REQS);
130 
131   ASSERT_EQ(write_cb_called, NUM_WRITE_REQS);
132   ASSERT_EQ(1, close_cb_called);
133 
134   MAKE_VALGRIND_HAPPY(loop);
135   return 0;
136 }
137