1/* Copyright libuv project and 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 29#define CHECK_HANDLE(handle) \ 30 ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) 31 32static uv_udp_t server; 33static uv_udp_t client; 34static uv_buf_t buf; 35static struct sockaddr_in6 lo_addr; 36 37static int cl_send_cb_called; 38static int sv_recv_cb_called; 39 40static int close_cb_called; 41 42 43static void alloc_cb(uv_handle_t* handle, 44 size_t suggested_size, 45 uv_buf_t* buf) { 46 static char slab[65536]; 47 CHECK_HANDLE(handle); 48 ASSERT_LE(suggested_size, sizeof(slab)); 49 buf->base = slab; 50 buf->len = sizeof(slab); 51} 52 53 54static void close_cb(uv_handle_t* handle) { 55 CHECK_HANDLE(handle); 56 ASSERT(uv_is_closing(handle)); 57 close_cb_called++; 58} 59 60 61static void cl_send_cb(uv_udp_send_t* req, int status) { 62 int r; 63 64 ASSERT_NOT_NULL(req); 65 ASSERT_OK(status); 66 CHECK_HANDLE(req->handle); 67 if (++cl_send_cb_called == 1) { 68 uv_udp_connect(&client, NULL); 69 r = uv_udp_send(req, &client, &buf, 1, NULL, cl_send_cb); 70 ASSERT_EQ(r, UV_EDESTADDRREQ); 71 r = uv_udp_send(req, 72 &client, 73 &buf, 74 1, 75 (const struct sockaddr*) &lo_addr, 76 cl_send_cb); 77 ASSERT_OK(r); 78 } 79 80} 81 82 83static void sv_recv_cb(uv_udp_t* handle, 84 ssize_t nread, 85 const uv_buf_t* rcvbuf, 86 const struct sockaddr* addr, 87 unsigned flags) { 88 if (nread > 0) { 89 ASSERT_EQ(4, nread); 90 ASSERT_NOT_NULL(addr); 91 ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); 92 if (++sv_recv_cb_called == 4) { 93 uv_close((uv_handle_t*) &server, close_cb); 94 uv_close((uv_handle_t*) &client, close_cb); 95 } 96 } 97} 98 99 100TEST_IMPL(udp_connect6) { 101#if defined(__OpenBSD__) 102 RETURN_SKIP("Test does not currently work in OpenBSD"); 103#endif 104 uv_udp_send_t req; 105 struct sockaddr_in6 ext_addr; 106 struct sockaddr_in6 tmp_addr; 107 int r; 108 int addrlen; 109 110 if (!can_ipv6()) 111 RETURN_SKIP("IPv6 not supported"); 112 113 ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &lo_addr)); 114 115 r = uv_udp_init(uv_default_loop(), &server); 116 ASSERT_OK(r); 117 118 r = uv_udp_bind(&server, (const struct sockaddr*) &lo_addr, 0); 119 ASSERT_OK(r); 120 121 r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); 122 ASSERT_OK(r); 123 124 r = uv_udp_init(uv_default_loop(), &client); 125 ASSERT_OK(r); 126 127 buf = uv_buf_init("EXIT", 4); 128 129 /* connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL */ 130 ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &tmp_addr)); 131 r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); 132#ifdef _WIN32 133 ASSERT_EQ(r, UV_EADDRNOTAVAIL); 134#else 135 ASSERT_OK(r); 136 r = uv_udp_connect(&client, NULL); 137 ASSERT_OK(r); 138#endif 139 140 ASSERT_OK(uv_ip6_addr("2001:4860:4860::8888", TEST_PORT, &ext_addr)); 141 ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &lo_addr)); 142 143 r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); 144 ASSERT_OK(r); 145 r = uv_udp_connect(&client, (const struct sockaddr*) &ext_addr); 146 ASSERT_EQ(r, UV_EISCONN); 147 148 addrlen = sizeof(tmp_addr); 149 r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); 150 ASSERT_OK(r); 151 152 /* To send messages in connected UDP sockets addr must be NULL */ 153 r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); 154 ASSERT_EQ(r, UV_EISCONN); 155 r = uv_udp_try_send(&client, &buf, 1, NULL); 156 ASSERT_EQ(4, r); 157 r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &ext_addr); 158 ASSERT_EQ(r, UV_EISCONN); 159 160 r = uv_udp_connect(&client, NULL); 161 ASSERT_OK(r); 162 r = uv_udp_connect(&client, NULL); 163 ASSERT_EQ(r, UV_ENOTCONN); 164 165 addrlen = sizeof(tmp_addr); 166 r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); 167 ASSERT_EQ(r, UV_ENOTCONN); 168 169 /* To send messages in disconnected UDP sockets addr must be set */ 170 r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); 171 ASSERT_EQ(4, r); 172 r = uv_udp_try_send(&client, &buf, 1, NULL); 173 ASSERT_EQ(r, UV_EDESTADDRREQ); 174 175 176 r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); 177 ASSERT_OK(r); 178 r = uv_udp_send(&req, 179 &client, 180 &buf, 181 1, 182 (const struct sockaddr*) &lo_addr, 183 cl_send_cb); 184 ASSERT_EQ(r, UV_EISCONN); 185 r = uv_udp_send(&req, &client, &buf, 1, NULL, cl_send_cb); 186 ASSERT_OK(r); 187 188 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 189 190 ASSERT_EQ(2, close_cb_called); 191 ASSERT_EQ(4, sv_recv_cb_called); 192 ASSERT_EQ(2, cl_send_cb_called); 193 194 ASSERT_OK(client.send_queue_size); 195 ASSERT_OK(server.send_queue_size); 196 197 MAKE_VALGRIND_HAPPY(uv_default_loop()); 198 return 0; 199} 200