test-tcp-open.c revision 1.1.1.1
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(r == 0); 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(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 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(r == 0); 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(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(handle != NULL); 100 close_cb_called++; 101} 102 103 104static 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 113static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { 114 ASSERT(tcp != NULL); 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 127static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { 128 int i; 129 ASSERT(tcp != NULL); 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 142static void write_cb(uv_write_t* req, int status) { 143 ASSERT(req != NULL); 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(req != NULL); 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 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(r == 0); 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(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 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(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 236TEST_IMPL(tcp_open) { 237 struct sockaddr_in addr; 238 uv_os_sock_t sock; 239 int r; 240 241 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 242 243 startup(); 244 sock = create_tcp_socket(); 245 246 r = uv_tcp_init(uv_default_loop(), &client); 247 ASSERT(r == 0); 248 249 r = uv_tcp_open(&client, sock); 250 ASSERT(r == 0); 251 252 r = uv_tcp_connect(&connect_req, 253 &client, 254 (const struct sockaddr*) &addr, 255 connect_cb); 256 ASSERT(r == 0); 257 258#ifndef _WIN32 259 { 260 uv_tcp_t client2; 261 262 r = uv_tcp_init(uv_default_loop(), &client2); 263 ASSERT(r == 0); 264 265 r = uv_tcp_open(&client2, sock); 266 ASSERT(r == UV_EEXIST); 267 268 uv_close((uv_handle_t*) &client2, NULL); 269 } 270#endif /* !_WIN32 */ 271 272 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 273 274 ASSERT(shutdown_cb_called == 1); 275 ASSERT(connect_cb_called == 1); 276 ASSERT(write_cb_called == 1); 277 ASSERT(close_cb_called == 1); 278 279 MAKE_VALGRIND_HAPPY(); 280 return 0; 281} 282 283 284TEST_IMPL(tcp_open_twice) { 285 uv_tcp_t client; 286 uv_os_sock_t sock1, sock2; 287 int r; 288 289 startup(); 290 sock1 = create_tcp_socket(); 291 sock2 = create_tcp_socket(); 292 293 r = uv_tcp_init(uv_default_loop(), &client); 294 ASSERT(r == 0); 295 296 r = uv_tcp_open(&client, sock1); 297 ASSERT(r == 0); 298 299 r = uv_tcp_open(&client, sock2); 300 ASSERT(r == UV_EBUSY); 301 close_socket(sock2); 302 303 uv_close((uv_handle_t*) &client, NULL); 304 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 305 306 MAKE_VALGRIND_HAPPY(); 307 return 0; 308} 309 310 311TEST_IMPL(tcp_open_bound) { 312 struct sockaddr_in addr; 313 uv_tcp_t server; 314 uv_os_sock_t sock; 315 316 startup(); 317 sock = create_tcp_socket(); 318 319 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 320 321 ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); 322 323 ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); 324 325 ASSERT(0 == uv_tcp_open(&server, sock)); 326 327 ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); 328 329 MAKE_VALGRIND_HAPPY(); 330 return 0; 331} 332 333 334TEST_IMPL(tcp_open_connected) { 335 struct sockaddr_in addr; 336 uv_tcp_t client; 337 uv_os_sock_t sock; 338 uv_buf_t buf = uv_buf_init("PING", 4); 339 340 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 341 342 startup(); 343 sock = create_tcp_socket(); 344 345 ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); 346 347 ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); 348 349 ASSERT(0 == uv_tcp_open(&client, sock)); 350 351 ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); 352 353 ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); 354 355 ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); 356 357 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 358 359 ASSERT(shutdown_cb_called == 1); 360 ASSERT(write_cb_called == 1); 361 ASSERT(close_cb_called == 1); 362 363 MAKE_VALGRIND_HAPPY(); 364 return 0; 365} 366 367 368TEST_IMPL(tcp_write_ready) { 369 struct sockaddr_in addr; 370 uv_os_sock_t sock; 371 int r; 372 373 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 374 375 startup(); 376 sock = create_tcp_socket(); 377 378 r = uv_tcp_init(uv_default_loop(), &client); 379 ASSERT(r == 0); 380 381 r = uv_tcp_open(&client, sock); 382 ASSERT(r == 0); 383 384 r = uv_tcp_connect(&connect_req, 385 &client, 386 (const struct sockaddr*) &addr, 387 connect1_cb); 388 ASSERT(r == 0); 389 390 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 391 392 ASSERT(shutdown_cb_called == 1); 393 ASSERT(shutdown_requested == 1); 394 ASSERT(connect_cb_called == 1); 395 ASSERT(write_cb_called > 0); 396 ASSERT(close_cb_called == 1); 397 398 MAKE_VALGRIND_HAPPY(); 399 return 0; 400} 401