xref: /netbsd-src/external/mit/libuv/dist/test/test-tcp-open.c (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
10e552da7Schristos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
20e552da7Schristos  *
30e552da7Schristos  * Permission is hereby granted, free of charge, to any person obtaining a copy
40e552da7Schristos  * of this software and associated documentation files (the "Software"), to
50e552da7Schristos  * deal in the Software without restriction, including without limitation the
60e552da7Schristos  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
70e552da7Schristos  * sell copies of the Software, and to permit persons to whom the Software is
80e552da7Schristos  * furnished to do so, subject to the following conditions:
90e552da7Schristos  *
100e552da7Schristos  * The above copyright notice and this permission notice shall be included in
110e552da7Schristos  * all copies or substantial portions of the Software.
120e552da7Schristos  *
130e552da7Schristos  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140e552da7Schristos  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
150e552da7Schristos  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
160e552da7Schristos  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
170e552da7Schristos  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
180e552da7Schristos  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
190e552da7Schristos  * IN THE SOFTWARE.
200e552da7Schristos  */
210e552da7Schristos 
220e552da7Schristos #include "uv.h"
230e552da7Schristos #include "task.h"
240e552da7Schristos #include <stdio.h>
250e552da7Schristos #include <stdlib.h>
260e552da7Schristos #include <string.h>
270e552da7Schristos 
280e552da7Schristos #ifndef _WIN32
290e552da7Schristos # include <unistd.h>
300e552da7Schristos #endif
310e552da7Schristos 
320e552da7Schristos static int shutdown_cb_called = 0;
330e552da7Schristos static int shutdown_requested = 0;
340e552da7Schristos static int connect_cb_called = 0;
350e552da7Schristos static int write_cb_called = 0;
360e552da7Schristos static int close_cb_called = 0;
370e552da7Schristos 
380e552da7Schristos static uv_connect_t connect_req;
390e552da7Schristos static uv_shutdown_t shutdown_req;
400e552da7Schristos static uv_write_t write_req;
410e552da7Schristos static uv_timer_t tm;
420e552da7Schristos static uv_tcp_t client;
430e552da7Schristos 
440e552da7Schristos 
startup(void)450e552da7Schristos static void startup(void) {
460e552da7Schristos #ifdef _WIN32
470e552da7Schristos     struct WSAData wsa_data;
480e552da7Schristos     int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
490e552da7Schristos     ASSERT(r == 0);
500e552da7Schristos #endif
510e552da7Schristos }
520e552da7Schristos 
530e552da7Schristos 
create_tcp_socket(void)540e552da7Schristos static uv_os_sock_t create_tcp_socket(void) {
550e552da7Schristos   uv_os_sock_t sock;
560e552da7Schristos 
570e552da7Schristos   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
580e552da7Schristos #ifdef _WIN32
590e552da7Schristos   ASSERT(sock != INVALID_SOCKET);
600e552da7Schristos #else
610e552da7Schristos   ASSERT(sock >= 0);
620e552da7Schristos #endif
630e552da7Schristos 
640e552da7Schristos #ifndef _WIN32
650e552da7Schristos   {
660e552da7Schristos     /* Allow reuse of the port. */
670e552da7Schristos     int yes = 1;
680e552da7Schristos     int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
690e552da7Schristos     ASSERT(r == 0);
700e552da7Schristos   }
710e552da7Schristos #endif
720e552da7Schristos 
730e552da7Schristos   return sock;
740e552da7Schristos }
750e552da7Schristos 
760e552da7Schristos 
close_socket(uv_os_sock_t sock)770e552da7Schristos static void close_socket(uv_os_sock_t sock) {
780e552da7Schristos   int r;
790e552da7Schristos #ifdef _WIN32
800e552da7Schristos   r = closesocket(sock);
810e552da7Schristos #else
820e552da7Schristos   r = close(sock);
830e552da7Schristos #endif
840e552da7Schristos   ASSERT(r == 0);
850e552da7Schristos }
860e552da7Schristos 
870e552da7Schristos 
alloc_cb(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)880e552da7Schristos static void alloc_cb(uv_handle_t* handle,
890e552da7Schristos                      size_t suggested_size,
900e552da7Schristos                      uv_buf_t* buf) {
910e552da7Schristos   static char slab[65536];
920e552da7Schristos   ASSERT(suggested_size <= sizeof(slab));
930e552da7Schristos   buf->base = slab;
940e552da7Schristos   buf->len = sizeof(slab);
950e552da7Schristos }
960e552da7Schristos 
970e552da7Schristos 
close_cb(uv_handle_t * handle)980e552da7Schristos static void close_cb(uv_handle_t* handle) {
99*5f2f4271Schristos   ASSERT_NOT_NULL(handle);
1000e552da7Schristos   close_cb_called++;
1010e552da7Schristos }
1020e552da7Schristos 
1030e552da7Schristos 
shutdown_cb(uv_shutdown_t * req,int status)1040e552da7Schristos static void shutdown_cb(uv_shutdown_t* req, int status) {
1050e552da7Schristos   ASSERT(req == &shutdown_req);
1060e552da7Schristos   ASSERT(status == 0);
1070e552da7Schristos 
1080e552da7Schristos   /* Now we wait for the EOF */
1090e552da7Schristos   shutdown_cb_called++;
1100e552da7Schristos }
1110e552da7Schristos 
1120e552da7Schristos 
read_cb(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)1130e552da7Schristos static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
114*5f2f4271Schristos   ASSERT_NOT_NULL(tcp);
1150e552da7Schristos 
1160e552da7Schristos   if (nread >= 0) {
1170e552da7Schristos     ASSERT(nread == 4);
1180e552da7Schristos     ASSERT(memcmp("PING", buf->base, nread) == 0);
1190e552da7Schristos   }
1200e552da7Schristos   else {
1210e552da7Schristos     ASSERT(nread == UV_EOF);
1220e552da7Schristos     uv_close((uv_handle_t*)tcp, close_cb);
1230e552da7Schristos   }
1240e552da7Schristos }
1250e552da7Schristos 
1260e552da7Schristos 
read1_cb(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)1270e552da7Schristos static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
1280e552da7Schristos   int i;
129*5f2f4271Schristos   ASSERT_NOT_NULL(tcp);
1300e552da7Schristos 
1310e552da7Schristos   if (nread >= 0) {
1320e552da7Schristos     for (i = 0; i < nread; ++i)
1330e552da7Schristos       ASSERT(buf->base[i] == 'P');
1340e552da7Schristos   } else {
1350e552da7Schristos     ASSERT(nread == UV_EOF);
1360e552da7Schristos     printf("GOT EOF\n");
1370e552da7Schristos     uv_close((uv_handle_t*)tcp, close_cb);
1380e552da7Schristos   }
1390e552da7Schristos }
1400e552da7Schristos 
1410e552da7Schristos 
write_cb(uv_write_t * req,int status)1420e552da7Schristos static void write_cb(uv_write_t* req, int status) {
143*5f2f4271Schristos   ASSERT_NOT_NULL(req);
1440e552da7Schristos 
1450e552da7Schristos   if (status) {
1460e552da7Schristos     fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
1470e552da7Schristos     ASSERT(0);
1480e552da7Schristos   }
1490e552da7Schristos 
1500e552da7Schristos   write_cb_called++;
1510e552da7Schristos }
1520e552da7Schristos 
1530e552da7Schristos 
write1_cb(uv_write_t * req,int status)1540e552da7Schristos static void write1_cb(uv_write_t* req, int status) {
1550e552da7Schristos   uv_buf_t buf;
1560e552da7Schristos   int r;
1570e552da7Schristos 
158*5f2f4271Schristos   ASSERT_NOT_NULL(req);
1590e552da7Schristos   if (status) {
1600e552da7Schristos     ASSERT(shutdown_cb_called);
1610e552da7Schristos     return;
1620e552da7Schristos   }
1630e552da7Schristos 
1640e552da7Schristos   if (shutdown_requested)
1650e552da7Schristos     return;
1660e552da7Schristos 
1670e552da7Schristos   buf = uv_buf_init("P", 1);
1680e552da7Schristos   r = uv_write(&write_req, req->handle, &buf, 1, write1_cb);
1690e552da7Schristos   ASSERT(r == 0);
1700e552da7Schristos 
1710e552da7Schristos   write_cb_called++;
1720e552da7Schristos }
1730e552da7Schristos 
1740e552da7Schristos 
timer_cb(uv_timer_t * handle)1750e552da7Schristos static void timer_cb(uv_timer_t* handle) {
1760e552da7Schristos   int r;
1770e552da7Schristos 
1780e552da7Schristos   /* Shutdown on drain. */
1790e552da7Schristos   r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb);
1800e552da7Schristos   ASSERT(r == 0);
1810e552da7Schristos   shutdown_requested++;
1820e552da7Schristos }
1830e552da7Schristos 
1840e552da7Schristos 
connect_cb(uv_connect_t * req,int status)1850e552da7Schristos static void connect_cb(uv_connect_t* req, int status) {
1860e552da7Schristos   uv_buf_t buf = uv_buf_init("PING", 4);
1870e552da7Schristos   uv_stream_t* stream;
1880e552da7Schristos   int r;
1890e552da7Schristos 
1900e552da7Schristos   ASSERT(req == &connect_req);
1910e552da7Schristos   ASSERT(status == 0);
1920e552da7Schristos 
1930e552da7Schristos   stream = req->handle;
1940e552da7Schristos   connect_cb_called++;
1950e552da7Schristos 
1960e552da7Schristos   r = uv_write(&write_req, stream, &buf, 1, write_cb);
1970e552da7Schristos   ASSERT(r == 0);
1980e552da7Schristos 
1990e552da7Schristos   /* Shutdown on drain. */
2000e552da7Schristos   r = uv_shutdown(&shutdown_req, stream, shutdown_cb);
2010e552da7Schristos   ASSERT(r == 0);
2020e552da7Schristos 
2030e552da7Schristos   /* Start reading */
2040e552da7Schristos   r = uv_read_start(stream, alloc_cb, read_cb);
2050e552da7Schristos   ASSERT(r == 0);
2060e552da7Schristos }
2070e552da7Schristos 
2080e552da7Schristos 
connect1_cb(uv_connect_t * req,int status)2090e552da7Schristos static void connect1_cb(uv_connect_t* req, int status) {
2100e552da7Schristos   uv_buf_t buf;
2110e552da7Schristos   uv_stream_t* stream;
2120e552da7Schristos   int r;
2130e552da7Schristos 
2140e552da7Schristos   ASSERT(req == &connect_req);
2150e552da7Schristos   ASSERT(status == 0);
2160e552da7Schristos 
2170e552da7Schristos   stream = req->handle;
2180e552da7Schristos   connect_cb_called++;
2190e552da7Schristos 
2200e552da7Schristos   r = uv_timer_init(uv_default_loop(), &tm);
2210e552da7Schristos   ASSERT(r == 0);
2220e552da7Schristos 
2230e552da7Schristos   r = uv_timer_start(&tm, timer_cb, 2000, 0);
2240e552da7Schristos   ASSERT(r == 0);
2250e552da7Schristos 
2260e552da7Schristos   buf = uv_buf_init("P", 1);
2270e552da7Schristos   r = uv_write(&write_req, stream, &buf, 1, write1_cb);
2280e552da7Schristos   ASSERT(r == 0);
2290e552da7Schristos 
2300e552da7Schristos   /* Start reading */
2310e552da7Schristos   r = uv_read_start(stream, alloc_cb, read1_cb);
2320e552da7Schristos   ASSERT(r == 0);
2330e552da7Schristos }
2340e552da7Schristos 
2350e552da7Schristos 
TEST_IMPL(tcp_open)2360e552da7Schristos TEST_IMPL(tcp_open) {
2370e552da7Schristos   struct sockaddr_in addr;
2380e552da7Schristos   uv_os_sock_t sock;
2390e552da7Schristos   int r;
240*5f2f4271Schristos   uv_tcp_t client2;
2410e552da7Schristos 
2420e552da7Schristos   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
2430e552da7Schristos 
2440e552da7Schristos   startup();
2450e552da7Schristos   sock = create_tcp_socket();
2460e552da7Schristos 
2470e552da7Schristos   r = uv_tcp_init(uv_default_loop(), &client);
2480e552da7Schristos   ASSERT(r == 0);
2490e552da7Schristos 
2500e552da7Schristos   r = uv_tcp_open(&client, sock);
2510e552da7Schristos   ASSERT(r == 0);
2520e552da7Schristos 
2530e552da7Schristos   r = uv_tcp_connect(&connect_req,
2540e552da7Schristos                      &client,
2550e552da7Schristos                      (const struct sockaddr*) &addr,
2560e552da7Schristos                      connect_cb);
2570e552da7Schristos   ASSERT(r == 0);
2580e552da7Schristos 
2590e552da7Schristos #ifndef _WIN32
2600e552da7Schristos   {
2610e552da7Schristos     r = uv_tcp_init(uv_default_loop(), &client2);
2620e552da7Schristos     ASSERT(r == 0);
2630e552da7Schristos 
2640e552da7Schristos     r = uv_tcp_open(&client2, sock);
2650e552da7Schristos     ASSERT(r == UV_EEXIST);
2660e552da7Schristos 
2670e552da7Schristos     uv_close((uv_handle_t*) &client2, NULL);
2680e552da7Schristos   }
269*5f2f4271Schristos #else  /* _WIN32 */
270*5f2f4271Schristos   (void)client2;
271*5f2f4271Schristos #endif
2720e552da7Schristos 
2730e552da7Schristos   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
2740e552da7Schristos 
2750e552da7Schristos   ASSERT(shutdown_cb_called == 1);
2760e552da7Schristos   ASSERT(connect_cb_called == 1);
2770e552da7Schristos   ASSERT(write_cb_called == 1);
2780e552da7Schristos   ASSERT(close_cb_called == 1);
2790e552da7Schristos 
2800e552da7Schristos   MAKE_VALGRIND_HAPPY();
2810e552da7Schristos   return 0;
2820e552da7Schristos }
2830e552da7Schristos 
2840e552da7Schristos 
TEST_IMPL(tcp_open_twice)2850e552da7Schristos TEST_IMPL(tcp_open_twice) {
2860e552da7Schristos   uv_tcp_t client;
2870e552da7Schristos   uv_os_sock_t sock1, sock2;
2880e552da7Schristos   int r;
2890e552da7Schristos 
2900e552da7Schristos   startup();
2910e552da7Schristos   sock1 = create_tcp_socket();
2920e552da7Schristos   sock2 = create_tcp_socket();
2930e552da7Schristos 
2940e552da7Schristos   r = uv_tcp_init(uv_default_loop(), &client);
2950e552da7Schristos   ASSERT(r == 0);
2960e552da7Schristos 
2970e552da7Schristos   r = uv_tcp_open(&client, sock1);
2980e552da7Schristos   ASSERT(r == 0);
2990e552da7Schristos 
3000e552da7Schristos   r = uv_tcp_open(&client, sock2);
3010e552da7Schristos   ASSERT(r == UV_EBUSY);
3020e552da7Schristos   close_socket(sock2);
3030e552da7Schristos 
3040e552da7Schristos   uv_close((uv_handle_t*) &client, NULL);
3050e552da7Schristos   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
3060e552da7Schristos 
3070e552da7Schristos   MAKE_VALGRIND_HAPPY();
3080e552da7Schristos   return 0;
3090e552da7Schristos }
3100e552da7Schristos 
3110e552da7Schristos 
TEST_IMPL(tcp_open_bound)3120e552da7Schristos TEST_IMPL(tcp_open_bound) {
3130e552da7Schristos   struct sockaddr_in addr;
3140e552da7Schristos   uv_tcp_t server;
3150e552da7Schristos   uv_os_sock_t sock;
3160e552da7Schristos 
3170e552da7Schristos   startup();
3180e552da7Schristos   sock = create_tcp_socket();
3190e552da7Schristos 
3200e552da7Schristos   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
3210e552da7Schristos 
3220e552da7Schristos   ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
3230e552da7Schristos 
3240e552da7Schristos   ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr)));
3250e552da7Schristos 
3260e552da7Schristos   ASSERT(0 == uv_tcp_open(&server, sock));
3270e552da7Schristos 
3280e552da7Schristos   ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL));
3290e552da7Schristos 
3300e552da7Schristos   MAKE_VALGRIND_HAPPY();
3310e552da7Schristos   return 0;
3320e552da7Schristos }
3330e552da7Schristos 
3340e552da7Schristos 
TEST_IMPL(tcp_open_connected)3350e552da7Schristos TEST_IMPL(tcp_open_connected) {
3360e552da7Schristos   struct sockaddr_in addr;
3370e552da7Schristos   uv_tcp_t client;
3380e552da7Schristos   uv_os_sock_t sock;
3390e552da7Schristos   uv_buf_t buf = uv_buf_init("PING", 4);
3400e552da7Schristos 
3410e552da7Schristos   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
3420e552da7Schristos 
3430e552da7Schristos   startup();
3440e552da7Schristos   sock = create_tcp_socket();
3450e552da7Schristos 
3460e552da7Schristos   ASSERT(0 == connect(sock, (struct sockaddr*) &addr,  sizeof(addr)));
3470e552da7Schristos 
3480e552da7Schristos   ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
3490e552da7Schristos 
3500e552da7Schristos   ASSERT(0 == uv_tcp_open(&client, sock));
3510e552da7Schristos 
3520e552da7Schristos   ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb));
3530e552da7Schristos 
3540e552da7Schristos   ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb));
3550e552da7Schristos 
3560e552da7Schristos   ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb));
3570e552da7Schristos 
3580e552da7Schristos   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
3590e552da7Schristos 
3600e552da7Schristos   ASSERT(shutdown_cb_called == 1);
3610e552da7Schristos   ASSERT(write_cb_called == 1);
3620e552da7Schristos   ASSERT(close_cb_called == 1);
3630e552da7Schristos 
3640e552da7Schristos   MAKE_VALGRIND_HAPPY();
3650e552da7Schristos   return 0;
3660e552da7Schristos }
3670e552da7Schristos 
3680e552da7Schristos 
TEST_IMPL(tcp_write_ready)3690e552da7Schristos TEST_IMPL(tcp_write_ready) {
3700e552da7Schristos   struct sockaddr_in addr;
3710e552da7Schristos   uv_os_sock_t sock;
3720e552da7Schristos   int r;
3730e552da7Schristos 
3740e552da7Schristos   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
3750e552da7Schristos 
3760e552da7Schristos   startup();
3770e552da7Schristos   sock = create_tcp_socket();
3780e552da7Schristos 
3790e552da7Schristos   r = uv_tcp_init(uv_default_loop(), &client);
3800e552da7Schristos   ASSERT(r == 0);
3810e552da7Schristos 
3820e552da7Schristos   r = uv_tcp_open(&client, sock);
3830e552da7Schristos   ASSERT(r == 0);
3840e552da7Schristos 
3850e552da7Schristos   r = uv_tcp_connect(&connect_req,
3860e552da7Schristos                      &client,
3870e552da7Schristos                      (const struct sockaddr*) &addr,
3880e552da7Schristos                      connect1_cb);
3890e552da7Schristos   ASSERT(r == 0);
3900e552da7Schristos 
3910e552da7Schristos   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
3920e552da7Schristos 
3930e552da7Schristos   ASSERT(shutdown_cb_called == 1);
3940e552da7Schristos   ASSERT(shutdown_requested == 1);
3950e552da7Schristos   ASSERT(connect_cb_called == 1);
3960e552da7Schristos   ASSERT(write_cb_called > 0);
3970e552da7Schristos   ASSERT(close_cb_called == 1);
3980e552da7Schristos 
3990e552da7Schristos   MAKE_VALGRIND_HAPPY();
4000e552da7Schristos   return 0;
4010e552da7Schristos }
402