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 22#include "uv.h" 23#include "task.h" 24 25#include <errno.h> 26#include <string.h> /* memset */ 27 28#ifdef _WIN32 29# define INVALID_FD (INVALID_HANDLE_VALUE) 30#else 31# define INVALID_FD (-1) 32#endif 33 34static uv_loop_t* loop; 35static uv_tcp_t tcp_server; 36static uv_tcp_t tcp_client; 37static uv_tcp_t tcp_accepted; 38static uv_connect_t connect_req; 39static uv_shutdown_t shutdown_req; 40static uv_write_t write_reqs[4]; 41 42static int client_close; 43static int shutdown_before_close; 44 45static int write_cb_called; 46static int close_cb_called; 47static int shutdown_cb_called; 48 49static void connect_cb(uv_connect_t* req, int status); 50static void write_cb(uv_write_t* req, int status); 51static void close_cb(uv_handle_t* handle); 52static void shutdown_cb(uv_shutdown_t* req, int status); 53 54static int read_size; 55 56 57static void do_write(uv_tcp_t* handle) { 58 uv_buf_t buf; 59 unsigned i; 60 int r; 61 62 buf = uv_buf_init("PING", 4); 63 for (i = 0; i < ARRAY_SIZE(write_reqs); i++) { 64 r = uv_write(&write_reqs[i], (uv_stream_t*) handle, &buf, 1, write_cb); 65 ASSERT_OK(r); 66 } 67} 68 69 70static void do_close(uv_tcp_t* handle) { 71 uv_os_fd_t fd; 72 int r; 73 74 if (shutdown_before_close == 1) { 75 ASSERT_OK(uv_shutdown(&shutdown_req, 76 (uv_stream_t*) handle, 77 shutdown_cb)); 78 ASSERT_EQ(UV_EINVAL, uv_tcp_close_reset(handle, close_cb)); 79 } else if (shutdown_before_close == 2) { 80 r = uv_fileno((const uv_handle_t*) handle, &fd); 81 ASSERT_OK(r); 82#ifdef _WIN32 83 ASSERT_PTR_NE(fd, INVALID_FD); 84 ASSERT_OK(shutdown((SOCKET)fd, SD_BOTH)); 85#else 86 ASSERT_NE(fd, INVALID_FD); 87 ASSERT_OK(shutdown(fd, SHUT_RDWR)); 88#endif 89 ASSERT_OK(uv_tcp_close_reset(handle, close_cb)); 90 } else { 91 ASSERT_OK(uv_tcp_close_reset(handle, close_cb)); 92 ASSERT_EQ(UV_ENOTCONN, uv_shutdown(&shutdown_req, (uv_stream_t*) handle, 93 shutdown_cb)); 94 } 95 96 uv_close((uv_handle_t*) &tcp_server, NULL); 97} 98 99static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { 100 static char slab[1024]; 101 buf->base = slab; 102 buf->len = sizeof(slab); 103} 104 105static void read_cb2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { 106 ASSERT_PTR_EQ((uv_tcp_t*)stream, &tcp_client); 107 if (nread == UV_EOF) 108 uv_close((uv_handle_t*) stream, NULL); 109} 110 111 112static void connect_cb(uv_connect_t* conn_req, int status) { 113 ASSERT_PTR_EQ(conn_req, &connect_req); 114 uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb2); 115 do_write(&tcp_client); 116 if (client_close) 117 do_close(&tcp_client); 118} 119 120 121static void write_cb(uv_write_t* req, int status) { 122 /* write callbacks should run before the close callback */ 123 ASSERT_OK(close_cb_called); 124 ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_client); 125 write_cb_called++; 126} 127 128 129static void close_cb(uv_handle_t* handle) { 130 if (client_close) 131 ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp_client); 132 else 133 ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp_accepted); 134 135 close_cb_called++; 136} 137 138static void shutdown_cb(uv_shutdown_t* req, int status) { 139 if (client_close) 140 ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &tcp_client); 141 else 142 ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &tcp_accepted); 143 144 shutdown_cb_called++; 145} 146 147 148static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { 149 ASSERT_PTR_EQ((uv_tcp_t*)stream, &tcp_accepted); 150 if (nread < 0) { 151 uv_close((uv_handle_t*) stream, NULL); 152 } else { 153 read_size += nread; 154 if (read_size == 16 && client_close == 0) 155 do_close(&tcp_accepted); 156 } 157} 158 159 160static void connection_cb(uv_stream_t* server, int status) { 161 ASSERT_OK(status); 162 163 ASSERT_OK(uv_tcp_init(loop, &tcp_accepted)); 164 ASSERT_OK(uv_accept(server, (uv_stream_t*) &tcp_accepted)); 165 166 uv_read_start((uv_stream_t*) &tcp_accepted, alloc_cb, read_cb); 167} 168 169 170static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { 171 struct sockaddr_in addr; 172 int r; 173 174 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 175 176 r = uv_tcp_init(loop, handle); 177 ASSERT_OK(r); 178 179 r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); 180 ASSERT_OK(r); 181 182 r = uv_listen((uv_stream_t*)handle, 128, connection_cb); 183 ASSERT_OK(r); 184} 185 186 187static void do_connect(uv_loop_t* loop, uv_tcp_t* tcp_client) { 188 struct sockaddr_in addr; 189 int r; 190 191 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 192 193 r = uv_tcp_init(loop, tcp_client); 194 ASSERT_OK(r); 195 196 r = uv_tcp_connect(&connect_req, 197 tcp_client, 198 (const struct sockaddr*) &addr, 199 connect_cb); 200 ASSERT_OK(r); 201} 202 203 204/* Check that pending write requests have their callbacks 205 * invoked when the handle is closed. 206 */ 207TEST_IMPL(tcp_close_reset_client) { 208 int r; 209 210 loop = uv_default_loop(); 211 212 start_server(loop, &tcp_server); 213 214 client_close = 1; 215 shutdown_before_close = 0; 216 217 do_connect(loop, &tcp_client); 218 219 ASSERT_OK(write_cb_called); 220 ASSERT_OK(close_cb_called); 221 ASSERT_OK(shutdown_cb_called); 222 223 r = uv_run(loop, UV_RUN_DEFAULT); 224 ASSERT_OK(r); 225 226 ASSERT_EQ(4, write_cb_called); 227 ASSERT_EQ(1, close_cb_called); 228 ASSERT_OK(shutdown_cb_called); 229 230 MAKE_VALGRIND_HAPPY(loop); 231 return 0; 232} 233 234TEST_IMPL(tcp_close_reset_client_after_shutdown) { 235 int r; 236 237 loop = uv_default_loop(); 238 239 start_server(loop, &tcp_server); 240 241 client_close = 1; 242 shutdown_before_close = 1; 243 244 do_connect(loop, &tcp_client); 245 246 ASSERT_OK(write_cb_called); 247 ASSERT_OK(close_cb_called); 248 ASSERT_OK(shutdown_cb_called); 249 250 r = uv_run(loop, UV_RUN_DEFAULT); 251 ASSERT_OK(r); 252 253 ASSERT_EQ(4, write_cb_called); 254 ASSERT_OK(close_cb_called); 255 ASSERT_EQ(1, shutdown_cb_called); 256 257 MAKE_VALGRIND_HAPPY(loop); 258 return 0; 259} 260 261TEST_IMPL(tcp_close_reset_accepted) { 262 int r; 263 264 loop = uv_default_loop(); 265 266 start_server(loop, &tcp_server); 267 268 client_close = 0; 269 shutdown_before_close = 0; 270 271 do_connect(loop, &tcp_client); 272 273 ASSERT_OK(write_cb_called); 274 ASSERT_OK(close_cb_called); 275 ASSERT_OK(shutdown_cb_called); 276 277 r = uv_run(loop, UV_RUN_DEFAULT); 278 ASSERT_OK(r); 279 280 ASSERT_EQ(4, write_cb_called); 281 ASSERT_EQ(1, close_cb_called); 282 ASSERT_OK(shutdown_cb_called); 283 284 MAKE_VALGRIND_HAPPY(loop); 285 return 0; 286} 287 288TEST_IMPL(tcp_close_reset_accepted_after_shutdown) { 289 int r; 290 291 loop = uv_default_loop(); 292 293 start_server(loop, &tcp_server); 294 295 client_close = 0; 296 shutdown_before_close = 1; 297 298 do_connect(loop, &tcp_client); 299 300 ASSERT_OK(write_cb_called); 301 ASSERT_OK(close_cb_called); 302 ASSERT_OK(shutdown_cb_called); 303 304 r = uv_run(loop, UV_RUN_DEFAULT); 305 ASSERT_OK(r); 306 307 ASSERT_EQ(4, write_cb_called); 308 ASSERT_OK(close_cb_called); 309 ASSERT_EQ(1, shutdown_cb_called); 310 311 MAKE_VALGRIND_HAPPY(loop); 312 return 0; 313} 314 315TEST_IMPL(tcp_close_reset_accepted_after_socket_shutdown) { 316 int r; 317 318 loop = uv_default_loop(); 319 320 start_server(loop, &tcp_server); 321 322 client_close = 0; 323 shutdown_before_close = 2; 324 325 do_connect(loop, &tcp_client); 326 327 ASSERT_OK(write_cb_called); 328 ASSERT_OK(close_cb_called); 329 ASSERT_OK(shutdown_cb_called); 330 331 r = uv_run(loop, UV_RUN_DEFAULT); 332 ASSERT_OK(r); 333 334 ASSERT_EQ(4, write_cb_called); 335 ASSERT_EQ(1, close_cb_called); 336 ASSERT_OK(shutdown_cb_called); 337 338 MAKE_VALGRIND_HAPPY(loop); 339 return 0; 340} 341