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 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #ifndef _WIN32 29 # include <unistd.h> 30 #endif 31 32 static int shutdown_cb_called = 0; 33 static int shutdown_requested = 0; 34 static int connect_cb_called = 0; 35 static int write_cb_called = 0; 36 static int close_cb_called = 0; 37 38 static uv_connect_t connect_req; 39 static uv_shutdown_t shutdown_req; 40 static uv_write_t write_req; 41 static uv_timer_t tm; 42 static uv_tcp_t client; 43 44 45 static void startup(void) { 46 #ifdef _WIN32 47 struct WSAData wsa_data; 48 int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); 49 ASSERT(r == 0); 50 #endif 51 } 52 53 54 static uv_os_sock_t create_tcp_socket(void) { 55 uv_os_sock_t sock; 56 57 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 58 #ifdef _WIN32 59 ASSERT(sock != INVALID_SOCKET); 60 #else 61 ASSERT(sock >= 0); 62 #endif 63 64 #ifndef _WIN32 65 { 66 /* Allow reuse of the port. */ 67 int yes = 1; 68 int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); 69 ASSERT(r == 0); 70 } 71 #endif 72 73 return sock; 74 } 75 76 77 static void close_socket(uv_os_sock_t sock) { 78 int r; 79 #ifdef _WIN32 80 r = closesocket(sock); 81 #else 82 r = close(sock); 83 #endif 84 ASSERT(r == 0); 85 } 86 87 88 static void alloc_cb(uv_handle_t* handle, 89 size_t suggested_size, 90 uv_buf_t* buf) { 91 static char slab[65536]; 92 ASSERT(suggested_size <= sizeof(slab)); 93 buf->base = slab; 94 buf->len = sizeof(slab); 95 } 96 97 98 static void close_cb(uv_handle_t* handle) { 99 ASSERT_NOT_NULL(handle); 100 close_cb_called++; 101 } 102 103 104 static void shutdown_cb(uv_shutdown_t* req, int status) { 105 ASSERT(req == &shutdown_req); 106 ASSERT(status == 0); 107 108 /* Now we wait for the EOF */ 109 shutdown_cb_called++; 110 } 111 112 113 static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { 114 ASSERT_NOT_NULL(tcp); 115 116 if (nread >= 0) { 117 ASSERT(nread == 4); 118 ASSERT(memcmp("PING", buf->base, nread) == 0); 119 } 120 else { 121 ASSERT(nread == UV_EOF); 122 uv_close((uv_handle_t*)tcp, close_cb); 123 } 124 } 125 126 127 static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { 128 int i; 129 ASSERT_NOT_NULL(tcp); 130 131 if (nread >= 0) { 132 for (i = 0; i < nread; ++i) 133 ASSERT(buf->base[i] == 'P'); 134 } else { 135 ASSERT(nread == UV_EOF); 136 printf("GOT EOF\n"); 137 uv_close((uv_handle_t*)tcp, close_cb); 138 } 139 } 140 141 142 static void write_cb(uv_write_t* req, int status) { 143 ASSERT_NOT_NULL(req); 144 145 if (status) { 146 fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); 147 ASSERT(0); 148 } 149 150 write_cb_called++; 151 } 152 153 154 static void write1_cb(uv_write_t* req, int status) { 155 uv_buf_t buf; 156 int r; 157 158 ASSERT_NOT_NULL(req); 159 if (status) { 160 ASSERT(shutdown_cb_called); 161 return; 162 } 163 164 if (shutdown_requested) 165 return; 166 167 buf = uv_buf_init("P", 1); 168 r = uv_write(&write_req, req->handle, &buf, 1, write1_cb); 169 ASSERT(r == 0); 170 171 write_cb_called++; 172 } 173 174 175 static void timer_cb(uv_timer_t* handle) { 176 int r; 177 178 /* Shutdown on drain. */ 179 r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb); 180 ASSERT(r == 0); 181 shutdown_requested++; 182 } 183 184 185 static void connect_cb(uv_connect_t* req, int status) { 186 uv_buf_t buf = uv_buf_init("PING", 4); 187 uv_stream_t* stream; 188 int r; 189 190 ASSERT(req == &connect_req); 191 ASSERT(status == 0); 192 193 stream = req->handle; 194 connect_cb_called++; 195 196 r = uv_write(&write_req, stream, &buf, 1, write_cb); 197 ASSERT(r == 0); 198 199 /* Shutdown on drain. */ 200 r = uv_shutdown(&shutdown_req, stream, shutdown_cb); 201 ASSERT(r == 0); 202 203 /* Start reading */ 204 r = uv_read_start(stream, alloc_cb, read_cb); 205 ASSERT(r == 0); 206 } 207 208 209 static void connect1_cb(uv_connect_t* req, int status) { 210 uv_buf_t buf; 211 uv_stream_t* stream; 212 int r; 213 214 ASSERT(req == &connect_req); 215 ASSERT(status == 0); 216 217 stream = req->handle; 218 connect_cb_called++; 219 220 r = uv_timer_init(uv_default_loop(), &tm); 221 ASSERT(r == 0); 222 223 r = uv_timer_start(&tm, timer_cb, 2000, 0); 224 ASSERT(r == 0); 225 226 buf = uv_buf_init("P", 1); 227 r = uv_write(&write_req, stream, &buf, 1, write1_cb); 228 ASSERT(r == 0); 229 230 /* Start reading */ 231 r = uv_read_start(stream, alloc_cb, read1_cb); 232 ASSERT(r == 0); 233 } 234 235 236 TEST_IMPL(tcp_open) { 237 struct sockaddr_in addr; 238 uv_os_sock_t sock; 239 int r; 240 uv_tcp_t client2; 241 242 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 243 244 startup(); 245 sock = create_tcp_socket(); 246 247 r = uv_tcp_init(uv_default_loop(), &client); 248 ASSERT(r == 0); 249 250 r = uv_tcp_open(&client, sock); 251 ASSERT(r == 0); 252 253 r = uv_tcp_connect(&connect_req, 254 &client, 255 (const struct sockaddr*) &addr, 256 connect_cb); 257 ASSERT(r == 0); 258 259 #ifndef _WIN32 260 { 261 r = uv_tcp_init(uv_default_loop(), &client2); 262 ASSERT(r == 0); 263 264 r = uv_tcp_open(&client2, sock); 265 ASSERT(r == UV_EEXIST); 266 267 uv_close((uv_handle_t*) &client2, NULL); 268 } 269 #else /* _WIN32 */ 270 (void)client2; 271 #endif 272 273 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 274 275 ASSERT(shutdown_cb_called == 1); 276 ASSERT(connect_cb_called == 1); 277 ASSERT(write_cb_called == 1); 278 ASSERT(close_cb_called == 1); 279 280 MAKE_VALGRIND_HAPPY(); 281 return 0; 282 } 283 284 285 TEST_IMPL(tcp_open_twice) { 286 uv_tcp_t client; 287 uv_os_sock_t sock1, sock2; 288 int r; 289 290 startup(); 291 sock1 = create_tcp_socket(); 292 sock2 = create_tcp_socket(); 293 294 r = uv_tcp_init(uv_default_loop(), &client); 295 ASSERT(r == 0); 296 297 r = uv_tcp_open(&client, sock1); 298 ASSERT(r == 0); 299 300 r = uv_tcp_open(&client, sock2); 301 ASSERT(r == UV_EBUSY); 302 close_socket(sock2); 303 304 uv_close((uv_handle_t*) &client, NULL); 305 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 306 307 MAKE_VALGRIND_HAPPY(); 308 return 0; 309 } 310 311 312 TEST_IMPL(tcp_open_bound) { 313 struct sockaddr_in addr; 314 uv_tcp_t server; 315 uv_os_sock_t sock; 316 317 startup(); 318 sock = create_tcp_socket(); 319 320 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 321 322 ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); 323 324 ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); 325 326 ASSERT(0 == uv_tcp_open(&server, sock)); 327 328 ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); 329 330 MAKE_VALGRIND_HAPPY(); 331 return 0; 332 } 333 334 335 TEST_IMPL(tcp_open_connected) { 336 struct sockaddr_in addr; 337 uv_tcp_t client; 338 uv_os_sock_t sock; 339 uv_buf_t buf = uv_buf_init("PING", 4); 340 341 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 342 343 startup(); 344 sock = create_tcp_socket(); 345 346 ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); 347 348 ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); 349 350 ASSERT(0 == uv_tcp_open(&client, sock)); 351 352 ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); 353 354 ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); 355 356 ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); 357 358 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 359 360 ASSERT(shutdown_cb_called == 1); 361 ASSERT(write_cb_called == 1); 362 ASSERT(close_cb_called == 1); 363 364 MAKE_VALGRIND_HAPPY(); 365 return 0; 366 } 367 368 369 TEST_IMPL(tcp_write_ready) { 370 struct sockaddr_in addr; 371 uv_os_sock_t sock; 372 int r; 373 374 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 375 376 startup(); 377 sock = create_tcp_socket(); 378 379 r = uv_tcp_init(uv_default_loop(), &client); 380 ASSERT(r == 0); 381 382 r = uv_tcp_open(&client, sock); 383 ASSERT(r == 0); 384 385 r = uv_tcp_connect(&connect_req, 386 &client, 387 (const struct sockaddr*) &addr, 388 connect1_cb); 389 ASSERT(r == 0); 390 391 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 392 393 ASSERT(shutdown_cb_called == 1); 394 ASSERT(shutdown_requested == 1); 395 ASSERT(connect_cb_called == 1); 396 ASSERT(write_cb_called > 0); 397 ASSERT(close_cb_called == 1); 398 399 MAKE_VALGRIND_HAPPY(); 400 return 0; 401 } 402