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# include <sys/socket.h> 31# include <sys/un.h> 32#endif 33 34static int send_cb_called = 0; 35static int close_cb_called = 0; 36 37static uv_udp_send_t send_req; 38 39 40static void startup(void) { 41#ifdef _WIN32 42 struct WSAData wsa_data; 43 int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); 44 ASSERT_OK(r); 45#endif 46} 47 48 49static uv_os_sock_t create_udp_socket(void) { 50 uv_os_sock_t sock; 51 52 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 53#ifdef _WIN32 54 ASSERT_NE(sock, INVALID_SOCKET); 55#else 56 ASSERT_GE(sock, 0); 57#endif 58 59#ifndef _WIN32 60 { 61 /* Allow reuse of the port. */ 62 int yes = 1; 63 int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); 64 ASSERT_OK(r); 65 } 66#endif 67 68 return sock; 69} 70 71 72static void close_socket(uv_os_sock_t sock) { 73 int r; 74#ifdef _WIN32 75 r = closesocket(sock); 76#else 77 r = close(sock); 78#endif 79 ASSERT_OK(r); 80} 81 82 83static void alloc_cb(uv_handle_t* handle, 84 size_t suggested_size, 85 uv_buf_t* buf) { 86 static char slab[65536]; 87 ASSERT_LE(suggested_size, sizeof(slab)); 88 buf->base = slab; 89 buf->len = sizeof(slab); 90} 91 92 93static void close_cb(uv_handle_t* handle) { 94 ASSERT_NOT_NULL(handle); 95 close_cb_called++; 96} 97 98 99static void recv_cb(uv_udp_t* handle, 100 ssize_t nread, 101 const uv_buf_t* buf, 102 const struct sockaddr* addr, 103 unsigned flags) { 104 int r; 105 106 if (nread < 0) { 107 ASSERT(0 && "unexpected error"); 108 } 109 110 if (nread == 0) { 111 /* Returning unused buffer. Don't count towards sv_recv_cb_called */ 112 ASSERT_NULL(addr); 113 return; 114 } 115 116 ASSERT_OK(flags); 117 118 ASSERT_NOT_NULL(addr); 119 ASSERT_EQ(4, nread); 120 ASSERT_OK(memcmp("PING", buf->base, nread)); 121 122 r = uv_udp_recv_stop(handle); 123 ASSERT_OK(r); 124 125 uv_close((uv_handle_t*) handle, close_cb); 126} 127 128 129static void send_cb(uv_udp_send_t* req, int status) { 130 ASSERT_NOT_NULL(req); 131 ASSERT_OK(status); 132 133 send_cb_called++; 134 uv_close((uv_handle_t*)req->handle, close_cb); 135} 136 137 138TEST_IMPL(udp_open) { 139 struct sockaddr_in addr; 140 uv_buf_t buf = uv_buf_init("PING", 4); 141 uv_udp_t client, client2; 142 uv_os_sock_t sock; 143 int r; 144 145 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 146 147 startup(); 148 sock = create_udp_socket(); 149 150 r = uv_udp_init(uv_default_loop(), &client); 151 ASSERT_OK(r); 152 153 r = uv_udp_open(&client, sock); 154 ASSERT_OK(r); 155 156 r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); 157 ASSERT_OK(r); 158 159 r = uv_udp_recv_start(&client, alloc_cb, recv_cb); 160 ASSERT_OK(r); 161 162 r = uv_udp_send(&send_req, 163 &client, 164 &buf, 165 1, 166 (const struct sockaddr*) &addr, 167 send_cb); 168 ASSERT_OK(r); 169 170#ifndef _WIN32 171 { 172 r = uv_udp_init(uv_default_loop(), &client2); 173 ASSERT_OK(r); 174 175 r = uv_udp_open(&client2, sock); 176 ASSERT_EQ(r, UV_EEXIST); 177 178 uv_close((uv_handle_t*) &client2, NULL); 179 } 180#else /* _WIN32 */ 181 (void)client2; 182#endif 183 184 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 185 186 ASSERT_EQ(1, send_cb_called); 187 ASSERT_EQ(1, close_cb_called); 188 189 ASSERT_OK(client.send_queue_size); 190 191 MAKE_VALGRIND_HAPPY(uv_default_loop()); 192 return 0; 193} 194 195 196TEST_IMPL(udp_open_twice) { 197 uv_udp_t client; 198 uv_os_sock_t sock1, sock2; 199 int r; 200 201 startup(); 202 sock1 = create_udp_socket(); 203 sock2 = create_udp_socket(); 204 205 r = uv_udp_init(uv_default_loop(), &client); 206 ASSERT_OK(r); 207 208 r = uv_udp_open(&client, sock1); 209 ASSERT_OK(r); 210 211 r = uv_udp_open(&client, sock2); 212 ASSERT_EQ(r, UV_EBUSY); 213 close_socket(sock2); 214 215 uv_close((uv_handle_t*) &client, NULL); 216 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 217 218 MAKE_VALGRIND_HAPPY(uv_default_loop()); 219 return 0; 220} 221 222TEST_IMPL(udp_open_bound) { 223 struct sockaddr_in addr; 224 uv_udp_t client; 225 uv_os_sock_t sock; 226 int r; 227 228 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 229 230 startup(); 231 sock = create_udp_socket(); 232 233 r = bind(sock, (struct sockaddr*) &addr, sizeof(addr)); 234 ASSERT_OK(r); 235 236 r = uv_udp_init(uv_default_loop(), &client); 237 ASSERT_OK(r); 238 239 r = uv_udp_open(&client, sock); 240 ASSERT_OK(r); 241 242 r = uv_udp_recv_start(&client, alloc_cb, recv_cb); 243 ASSERT_OK(r); 244 245 uv_close((uv_handle_t*) &client, NULL); 246 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 247 248 MAKE_VALGRIND_HAPPY(uv_default_loop()); 249 return 0; 250} 251 252TEST_IMPL(udp_open_connect) { 253 struct sockaddr_in addr; 254 uv_buf_t buf = uv_buf_init("PING", 4); 255 uv_udp_t client; 256 uv_udp_t server; 257 uv_os_sock_t sock; 258 int r; 259 260 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 261 262 startup(); 263 sock = create_udp_socket(); 264 265 r = uv_udp_init(uv_default_loop(), &client); 266 ASSERT_OK(r); 267 268 r = connect(sock, (const struct sockaddr*) &addr, sizeof(addr)); 269 ASSERT_OK(r); 270 271 r = uv_udp_open(&client, sock); 272 ASSERT_OK(r); 273 274 r = uv_udp_init(uv_default_loop(), &server); 275 ASSERT_OK(r); 276 277 r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); 278 ASSERT_OK(r); 279 280 r = uv_udp_recv_start(&server, alloc_cb, recv_cb); 281 ASSERT_OK(r); 282 283 r = uv_udp_send(&send_req, 284 &client, 285 &buf, 286 1, 287 NULL, 288 send_cb); 289 ASSERT_OK(r); 290 291 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 292 293 ASSERT_EQ(1, send_cb_called); 294 ASSERT_EQ(2, close_cb_called); 295 296 ASSERT_OK(client.send_queue_size); 297 298 MAKE_VALGRIND_HAPPY(uv_default_loop()); 299 return 0; 300} 301 302#ifndef _WIN32 303TEST_IMPL(udp_send_unix) { 304 /* Test that "uv_udp_send()" supports sending over 305 a "sockaddr_un" address. */ 306 struct sockaddr_un addr; 307 uv_udp_t handle; 308 uv_udp_send_t req; 309 uv_loop_t* loop; 310 uv_buf_t buf = uv_buf_init("PING", 4); 311 int fd; 312 int r; 313 314 loop = uv_default_loop(); 315 316 memset(&addr, 0, sizeof addr); 317 addr.sun_family = AF_UNIX; 318 ASSERT_LT(strlen(TEST_PIPENAME), sizeof(addr.sun_path)); 319 memcpy(addr.sun_path, TEST_PIPENAME, strlen(TEST_PIPENAME)); 320 321 fd = socket(AF_UNIX, SOCK_STREAM, 0); 322 ASSERT_GE(fd, 0); 323 324 unlink(TEST_PIPENAME); 325 ASSERT_OK(bind(fd, (const struct sockaddr*)&addr, sizeof addr)); 326 ASSERT_OK(listen(fd, 1)); 327 328 r = uv_udp_init(loop, &handle); 329 ASSERT_OK(r); 330 r = uv_udp_open(&handle, fd); 331 ASSERT_OK(r); 332 uv_run(loop, UV_RUN_DEFAULT); 333 334 r = uv_udp_send(&req, 335 &handle, 336 &buf, 337 1, 338 (const struct sockaddr*) &addr, 339 NULL); 340 ASSERT_OK(r); 341 342 uv_close((uv_handle_t*)&handle, NULL); 343 uv_run(loop, UV_RUN_DEFAULT); 344 close(fd); 345 unlink(TEST_PIPENAME); 346 347 MAKE_VALGRIND_HAPPY(loop); 348 return 0; 349} 350#endif 351