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 32static int shutdown_cb_called = 0; 33static int shutdown_requested = 0; 34static int connect_cb_called = 0; 35static int write_cb_called = 0; 36static int close_cb_called = 0; 37 38static uv_connect_t connect_req; 39static uv_shutdown_t shutdown_req; 40static uv_write_t write_req; 41static uv_timer_t tm; 42static uv_tcp_t client; 43 44 45static void startup(void) { 46#ifdef _WIN32 47 struct WSAData wsa_data; 48 int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); 49 ASSERT_OK(r); 50#endif 51} 52 53 54static 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_NE(sock, INVALID_SOCKET); 60#else 61 ASSERT_GE(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_OK(r); 70 } 71#endif 72 73 return sock; 74} 75 76 77static 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_OK(r); 85} 86 87 88static void alloc_cb(uv_handle_t* handle, 89 size_t suggested_size, 90 uv_buf_t* buf) { 91 static char slab[65536]; 92 ASSERT_LE(suggested_size, sizeof(slab)); 93 buf->base = slab; 94 buf->len = sizeof(slab); 95} 96 97 98static void close_cb(uv_handle_t* handle) { 99 ASSERT_NOT_NULL(handle); 100 close_cb_called++; 101} 102 103 104static void shutdown_cb(uv_shutdown_t* req, int status) { 105 ASSERT_PTR_EQ(req, &shutdown_req); 106 ASSERT_OK(status); 107 108 /* Now we wait for the EOF */ 109 shutdown_cb_called++; 110} 111 112 113static 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_EQ(4, nread); 118 ASSERT_OK(memcmp("PING", buf->base, nread)); 119 } 120 else { 121 ASSERT_EQ(nread, UV_EOF); 122 uv_close((uv_handle_t*)tcp, close_cb); 123 } 124} 125 126 127static 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_EQ(buf->base[i], 'P'); 134 } else { 135 ASSERT_EQ(nread, UV_EOF); 136 printf("GOT EOF\n"); 137 uv_close((uv_handle_t*)tcp, close_cb); 138 } 139} 140 141 142static 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 154static 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_OK(r); 170 171 write_cb_called++; 172} 173 174 175static 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_OK(r); 181 shutdown_requested++; 182} 183 184 185static 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_PTR_EQ(req, &connect_req); 191 ASSERT_OK(status); 192 193 stream = req->handle; 194 connect_cb_called++; 195 196 r = uv_write(&write_req, stream, &buf, 1, write_cb); 197 ASSERT_OK(r); 198 199 /* Shutdown on drain. */ 200 r = uv_shutdown(&shutdown_req, stream, shutdown_cb); 201 ASSERT_OK(r); 202 203 /* Start reading */ 204 r = uv_read_start(stream, alloc_cb, read_cb); 205 ASSERT_OK(r); 206} 207 208 209static 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_PTR_EQ(req, &connect_req); 215 ASSERT_OK(status); 216 217 stream = req->handle; 218 connect_cb_called++; 219 220 r = uv_timer_init(uv_default_loop(), &tm); 221 ASSERT_OK(r); 222 223 r = uv_timer_start(&tm, timer_cb, 2000, 0); 224 ASSERT_OK(r); 225 226 buf = uv_buf_init("P", 1); 227 r = uv_write(&write_req, stream, &buf, 1, write1_cb); 228 ASSERT_OK(r); 229 230 /* Start reading */ 231 r = uv_read_start(stream, alloc_cb, read1_cb); 232 ASSERT_OK(r); 233} 234 235 236TEST_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_OK(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_OK(r); 249 250 r = uv_tcp_open(&client, sock); 251 ASSERT_OK(r); 252 253 r = uv_tcp_connect(&connect_req, 254 &client, 255 (const struct sockaddr*) &addr, 256 connect_cb); 257 ASSERT_OK(r); 258 259#ifndef _WIN32 260 { 261 r = uv_tcp_init(uv_default_loop(), &client2); 262 ASSERT_OK(r); 263 264 r = uv_tcp_open(&client2, sock); 265 ASSERT_EQ(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_EQ(1, shutdown_cb_called); 276 ASSERT_EQ(1, connect_cb_called); 277 ASSERT_EQ(1, write_cb_called); 278 ASSERT_EQ(1, close_cb_called); 279 280 MAKE_VALGRIND_HAPPY(uv_default_loop()); 281 return 0; 282} 283 284 285TEST_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_OK(r); 296 297 r = uv_tcp_open(&client, sock1); 298 ASSERT_OK(r); 299 300 r = uv_tcp_open(&client, sock2); 301 ASSERT_EQ(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(uv_default_loop()); 308 return 0; 309} 310 311 312TEST_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_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 321 322 ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); 323 324 ASSERT_OK(bind(sock, (struct sockaddr*) &addr, sizeof(addr))); 325 326 ASSERT_OK(uv_tcp_open(&server, sock)); 327 328 ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, NULL)); 329 330 MAKE_VALGRIND_HAPPY(uv_default_loop()); 331 return 0; 332} 333 334 335TEST_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_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 342 343 startup(); 344 sock = create_tcp_socket(); 345 346 ASSERT_OK(connect(sock, (struct sockaddr*) &addr, sizeof(addr))); 347 348 ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); 349 350 ASSERT_OK(uv_tcp_open(&client, sock)); 351 352 ASSERT_OK(uv_write(&write_req, 353 (uv_stream_t*) &client, 354 &buf, 355 1, 356 write_cb)); 357 358 ASSERT_OK(uv_shutdown(&shutdown_req, 359 (uv_stream_t*) &client, 360 shutdown_cb)); 361 362 ASSERT_OK(uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); 363 364 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 365 366 ASSERT_EQ(1, shutdown_cb_called); 367 ASSERT_EQ(1, write_cb_called); 368 ASSERT_EQ(1, close_cb_called); 369 370 MAKE_VALGRIND_HAPPY(uv_default_loop()); 371 return 0; 372} 373 374 375TEST_IMPL(tcp_write_ready) { 376 struct sockaddr_in addr; 377 uv_os_sock_t sock; 378 int r; 379 380 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 381 382 startup(); 383 sock = create_tcp_socket(); 384 385 r = uv_tcp_init(uv_default_loop(), &client); 386 ASSERT_OK(r); 387 388 r = uv_tcp_open(&client, sock); 389 ASSERT_OK(r); 390 391 r = uv_tcp_connect(&connect_req, 392 &client, 393 (const struct sockaddr*) &addr, 394 connect1_cb); 395 ASSERT_OK(r); 396 397 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 398 399 ASSERT_EQ(1, shutdown_cb_called); 400 ASSERT_EQ(1, shutdown_requested); 401 ASSERT_EQ(1, connect_cb_called); 402 ASSERT_GT(write_cb_called, 0); 403 ASSERT_EQ(1, close_cb_called); 404 405 MAKE_VALGRIND_HAPPY(uv_default_loop()); 406 return 0; 407} 408