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 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28 29static const int server_port = TEST_PORT; 30/* Will be updated right after making the uv_connect_call */ 31static int connect_port = -1; 32 33static int getsocknamecount_tcp = 0; 34static int getpeernamecount = 0; 35static int getsocknamecount_udp = 0; 36 37static uv_loop_t* loop; 38static uv_tcp_t tcp; 39static uv_udp_t udp; 40static uv_connect_t connect_req; 41static uv_tcp_t tcpServer; 42static uv_udp_t udpServer; 43static uv_udp_send_t send_req; 44 45 46static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 47 buf->base = malloc(suggested_size); 48 buf->len = suggested_size; 49} 50 51 52static void on_close(uv_handle_t* peer) { 53 free(peer); 54 uv_close((uv_handle_t*)&tcpServer, NULL); 55} 56 57 58static void after_shutdown(uv_shutdown_t* req, int status) { 59 uv_close((uv_handle_t*) req->handle, on_close); 60 free(req); 61} 62 63 64static void after_read(uv_stream_t* handle, 65 ssize_t nread, 66 const uv_buf_t* buf) { 67 uv_shutdown_t* req; 68 int r; 69 70 if (buf->base) { 71 free(buf->base); 72 } 73 74 req = (uv_shutdown_t*) malloc(sizeof *req); 75 r = uv_shutdown(req, handle, after_shutdown); 76 ASSERT(r == 0); 77} 78 79 80static void check_sockname(struct sockaddr* addr, const char* compare_ip, 81 int compare_port, const char* context) { 82 struct sockaddr_in check_addr = *(struct sockaddr_in*) addr; 83 struct sockaddr_in compare_addr; 84 char check_ip[17]; 85 int r; 86 87 ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr)); 88 89 /* Both addresses should be ipv4 */ 90 ASSERT(check_addr.sin_family == AF_INET); 91 ASSERT(compare_addr.sin_family == AF_INET); 92 93 /* Check if the ip matches */ 94 ASSERT(memcmp(&check_addr.sin_addr, 95 &compare_addr.sin_addr, 96 sizeof compare_addr.sin_addr) == 0); 97 98 /* Check if the port matches. If port == 0 anything goes. */ 99 ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port); 100 101 r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip); 102 ASSERT(r == 0); 103 104 printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port)); 105} 106 107 108static void on_connection(uv_stream_t* server, int status) { 109 struct sockaddr sockname, peername; 110 int namelen; 111 uv_tcp_t* handle; 112 int r; 113 114 if (status != 0) { 115 fprintf(stderr, "Connect error %s\n", uv_err_name(status)); 116 } 117 ASSERT(status == 0); 118 119 handle = malloc(sizeof(*handle)); 120 ASSERT_NOT_NULL(handle); 121 122 r = uv_tcp_init(loop, handle); 123 ASSERT(r == 0); 124 125 /* associate server with stream */ 126 handle->data = server; 127 128 r = uv_accept(server, (uv_stream_t*)handle); 129 ASSERT(r == 0); 130 131 namelen = sizeof sockname; 132 r = uv_tcp_getsockname(handle, &sockname, &namelen); 133 ASSERT(r == 0); 134 check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket"); 135 getsocknamecount_tcp++; 136 137 namelen = sizeof peername; 138 r = uv_tcp_getpeername(handle, &peername, &namelen); 139 ASSERT(r == 0); 140 check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer"); 141 getpeernamecount++; 142 143 r = uv_read_start((uv_stream_t*)handle, alloc, after_read); 144 ASSERT(r == 0); 145} 146 147 148static void on_connect(uv_connect_t* req, int status) { 149 struct sockaddr sockname, peername; 150 int r, namelen; 151 152 ASSERT(status == 0); 153 154 namelen = sizeof sockname; 155 r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen); 156 ASSERT(r == 0); 157 check_sockname(&sockname, "127.0.0.1", 0, "connected socket"); 158 getsocknamecount_tcp++; 159 160 namelen = sizeof peername; 161 r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen); 162 ASSERT(r == 0); 163 check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer"); 164 getpeernamecount++; 165 166 uv_close((uv_handle_t*)&tcp, NULL); 167} 168 169 170static int tcp_listener(void) { 171 struct sockaddr_in addr; 172 struct sockaddr sockname, peername; 173 int namelen; 174 int r; 175 176 ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); 177 178 r = uv_tcp_init(loop, &tcpServer); 179 if (r) { 180 fprintf(stderr, "Socket creation error\n"); 181 return 1; 182 } 183 184 r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0); 185 if (r) { 186 fprintf(stderr, "Bind error\n"); 187 return 1; 188 } 189 190 r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection); 191 if (r) { 192 fprintf(stderr, "Listen error\n"); 193 return 1; 194 } 195 196 memset(&sockname, -1, sizeof sockname); 197 namelen = sizeof sockname; 198 r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen); 199 ASSERT(r == 0); 200 check_sockname(&sockname, "0.0.0.0", server_port, "server socket"); 201 getsocknamecount_tcp++; 202 203 namelen = sizeof sockname; 204 r = uv_tcp_getpeername(&tcpServer, &peername, &namelen); 205 ASSERT(r == UV_ENOTCONN); 206 getpeernamecount++; 207 208 return 0; 209} 210 211 212static void tcp_connector(void) { 213 struct sockaddr_in server_addr; 214 struct sockaddr sockname; 215 int r, namelen; 216 217 ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); 218 219 r = uv_tcp_init(loop, &tcp); 220 tcp.data = &connect_req; 221 ASSERT(!r); 222 223 r = uv_tcp_connect(&connect_req, 224 &tcp, 225 (const struct sockaddr*) &server_addr, 226 on_connect); 227 ASSERT(!r); 228 229 /* Fetch the actual port used by the connecting socket. */ 230 namelen = sizeof sockname; 231 r = uv_tcp_getsockname(&tcp, &sockname, &namelen); 232 ASSERT(!r); 233 ASSERT(sockname.sa_family == AF_INET); 234 connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port); 235 ASSERT(connect_port > 0); 236} 237 238 239static void udp_recv(uv_udp_t* handle, 240 ssize_t nread, 241 const uv_buf_t* buf, 242 const struct sockaddr* addr, 243 unsigned flags) { 244 struct sockaddr sockname; 245 int namelen; 246 int r; 247 248 ASSERT(nread >= 0); 249 free(buf->base); 250 251 if (nread == 0) { 252 return; 253 } 254 255 memset(&sockname, -1, sizeof sockname); 256 namelen = sizeof(sockname); 257 r = uv_udp_getsockname(&udp, &sockname, &namelen); 258 ASSERT(r == 0); 259 check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket"); 260 getsocknamecount_udp++; 261 262 uv_close((uv_handle_t*) &udp, NULL); 263 uv_close((uv_handle_t*) handle, NULL); 264} 265 266 267static void udp_send(uv_udp_send_t* req, int status) { 268 269} 270 271 272static int udp_listener(void) { 273 struct sockaddr_in addr; 274 struct sockaddr sockname; 275 int namelen; 276 int r; 277 278 ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); 279 280 r = uv_udp_init(loop, &udpServer); 281 if (r) { 282 fprintf(stderr, "Socket creation error\n"); 283 return 1; 284 } 285 286 r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0); 287 if (r) { 288 fprintf(stderr, "Bind error\n"); 289 return 1; 290 } 291 292 memset(&sockname, -1, sizeof sockname); 293 namelen = sizeof sockname; 294 r = uv_udp_getsockname(&udpServer, &sockname, &namelen); 295 ASSERT(r == 0); 296 check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket"); 297 getsocknamecount_udp++; 298 299 r = uv_udp_recv_start(&udpServer, alloc, udp_recv); 300 ASSERT(r == 0); 301 302 return 0; 303} 304 305 306static void udp_sender(void) { 307 struct sockaddr_in server_addr; 308 uv_buf_t buf; 309 int r; 310 311 r = uv_udp_init(loop, &udp); 312 ASSERT(!r); 313 314 buf = uv_buf_init("PING", 4); 315 ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); 316 317 r = uv_udp_send(&send_req, 318 &udp, 319 &buf, 320 1, 321 (const struct sockaddr*) &server_addr, 322 udp_send); 323 ASSERT(!r); 324} 325 326 327TEST_IMPL(getsockname_tcp) { 328 loop = uv_default_loop(); 329 330 if (tcp_listener()) 331 return 1; 332 333 tcp_connector(); 334 335 uv_run(loop, UV_RUN_DEFAULT); 336 337 ASSERT(getsocknamecount_tcp == 3); 338 ASSERT(getpeernamecount == 3); 339 340 MAKE_VALGRIND_HAPPY(); 341 return 0; 342} 343 344 345TEST_IMPL(getsockname_udp) { 346 loop = uv_default_loop(); 347 348 if (udp_listener()) 349 return 1; 350 351 udp_sender(); 352 353 uv_run(loop, UV_RUN_DEFAULT); 354 355 ASSERT(getsocknamecount_udp == 2); 356 357 ASSERT(udp.send_queue_size == 0); 358 ASSERT(udpServer.send_queue_size == 0); 359 360 MAKE_VALGRIND_HAPPY(); 361 return 0; 362} 363