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 27 28static int connect_cb_called; 29static int close_cb_called; 30 31static uv_connect_t connect_req; 32static uv_timer_t timer; 33static uv_tcp_t conn; 34 35static void connect_cb(uv_connect_t* req, int status); 36static void timer_cb(uv_timer_t* handle); 37static void close_cb(uv_handle_t* handle); 38 39 40static void connect_cb(uv_connect_t* req, int status) { 41 ASSERT(req == &connect_req); 42 ASSERT(status == UV_ECANCELED); 43 connect_cb_called++; 44} 45 46 47static void timer_cb(uv_timer_t* handle) { 48 ASSERT(handle == &timer); 49 uv_close((uv_handle_t*)&conn, close_cb); 50 uv_close((uv_handle_t*)&timer, close_cb); 51} 52 53 54static void close_cb(uv_handle_t* handle) { 55 ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer); 56 close_cb_called++; 57} 58 59 60/* Verify that connecting to an unreachable address or port doesn't hang 61 * the event loop. 62 */ 63TEST_IMPL(tcp_connect_timeout) { 64 struct sockaddr_in addr; 65 int r; 66 67 ASSERT(0 == uv_ip4_addr("8.8.8.8", 9999, &addr)); 68 69 r = uv_timer_init(uv_default_loop(), &timer); 70 ASSERT(r == 0); 71 72 r = uv_timer_start(&timer, timer_cb, 50, 0); 73 ASSERT(r == 0); 74 75 r = uv_tcp_init(uv_default_loop(), &conn); 76 ASSERT(r == 0); 77 78 r = uv_tcp_connect(&connect_req, 79 &conn, 80 (const struct sockaddr*) &addr, 81 connect_cb); 82 if (r == UV_ENETUNREACH) 83 RETURN_SKIP("Network unreachable."); 84 ASSERT(r == 0); 85 86 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 87 ASSERT(r == 0); 88 89 MAKE_VALGRIND_HAPPY(); 90 return 0; 91} 92 93/* Make sure connect fails instantly if the target is nonexisting 94 * local port. 95 */ 96 97static void connect_local_cb(uv_connect_t* req, int status) { 98 ASSERT_PTR_EQ(req, &connect_req); 99 ASSERT_NE(status, UV_ECANCELED); 100 connect_cb_called++; 101} 102 103static int is_supported_system(void) { 104 int semver[3]; 105 int min_semver[3] = {10, 0, 16299}; 106 int cnt; 107 uv_utsname_t uname; 108 ASSERT_EQ(uv_os_uname(&uname), 0); 109 if (strcmp(uname.sysname, "Windows_NT") == 0) { 110 cnt = sscanf(uname.release, "%d.%d.%d", &semver[0], &semver[1], &semver[2]); 111 if (cnt != 3) { 112 return 0; 113 } 114 /* release >= 10.0.16299 */ 115 for (cnt = 0; cnt < 3; ++cnt) { 116 if (semver[cnt] > min_semver[cnt]) 117 return 1; 118 if (semver[cnt] < min_semver[cnt]) 119 return 0; 120 } 121 return 1; 122 } 123 return 1; 124} 125 126TEST_IMPL(tcp_local_connect_timeout) { 127 struct sockaddr_in addr; 128 int r; 129 130 if (!is_supported_system()) { 131 RETURN_SKIP("Unsupported system"); 132 } 133 ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 134 135 r = uv_timer_init(uv_default_loop(), &timer); 136 ASSERT_EQ(r, 0); 137 138 /* Give it 1s to timeout. */ 139 r = uv_timer_start(&timer, timer_cb, 1000, 0); 140 ASSERT_EQ(r, 0); 141 142 r = uv_tcp_init(uv_default_loop(), &conn); 143 ASSERT_EQ(r, 0); 144 145 r = uv_tcp_connect(&connect_req, 146 &conn, 147 (const struct sockaddr*) &addr, 148 connect_local_cb); 149 if (r == UV_ENETUNREACH) 150 RETURN_SKIP("Network unreachable."); 151 ASSERT_EQ(r, 0); 152 153 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 154 ASSERT(r == 0); 155 156 MAKE_VALGRIND_HAPPY(); 157 return 0; 158} 159 160TEST_IMPL(tcp6_local_connect_timeout) { 161 struct sockaddr_in6 addr; 162 int r; 163 164 if (!is_supported_system()) { 165 RETURN_SKIP("Unsupported system"); 166 } 167 if (!can_ipv6()) { 168 RETURN_SKIP("IPv6 not supported"); 169 } 170 171 ASSERT_EQ(0, uv_ip6_addr("::1", 9999, &addr)); 172 173 r = uv_timer_init(uv_default_loop(), &timer); 174 ASSERT_EQ(r, 0); 175 176 /* Give it 1s to timeout. */ 177 r = uv_timer_start(&timer, timer_cb, 1000, 0); 178 ASSERT_EQ(r, 0); 179 180 r = uv_tcp_init(uv_default_loop(), &conn); 181 ASSERT_EQ(r, 0); 182 183 r = uv_tcp_connect(&connect_req, 184 &conn, 185 (const struct sockaddr*) &addr, 186 connect_local_cb); 187 if (r == UV_ENETUNREACH) 188 RETURN_SKIP("Network unreachable."); 189 ASSERT_EQ(r, 0); 190 191 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 192 ASSERT_EQ(r, 0); 193 194 MAKE_VALGRIND_HAPPY(); 195 return 0; 196} 197