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 | |
29 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
30 | #include <sys/sysctl.h> |
31 | #endif |
32 | |
33 | #define CHECK_HANDLE(handle) \ |
34 | ASSERT((uv_udp_t*)(handle) == &server \ |
35 | || (uv_udp_t*)(handle) == &client \ |
36 | || (uv_timer_t*)(handle) == &timeout) |
37 | |
38 | #define CHECK_REQ(req) \ |
39 | ASSERT((req) == &req_); |
40 | |
41 | static uv_udp_t client; |
42 | static uv_udp_t server; |
43 | static uv_udp_send_t req_; |
44 | static uv_timer_t timeout; |
45 | |
46 | static int send_cb_called; |
47 | static int recv_cb_called; |
48 | static int close_cb_called; |
49 | |
50 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
51 | static int can_ipv6_ipv4_dual(void) { |
52 | int v6only; |
53 | size_t size = sizeof(int); |
54 | |
55 | if (sysctlbyname("net.inet6.ip6.v6only" , &v6only, &size, NULL, 0)) |
56 | return 0; |
57 | |
58 | return v6only != 1; |
59 | } |
60 | #endif |
61 | |
62 | |
63 | static void alloc_cb(uv_handle_t* handle, |
64 | size_t suggested_size, |
65 | uv_buf_t* buf) { |
66 | static char slab[65536]; |
67 | CHECK_HANDLE(handle); |
68 | buf->base = slab; |
69 | buf->len = sizeof(slab); |
70 | } |
71 | |
72 | |
73 | static void close_cb(uv_handle_t* handle) { |
74 | CHECK_HANDLE(handle); |
75 | close_cb_called++; |
76 | } |
77 | |
78 | |
79 | static void send_cb(uv_udp_send_t* req, int status) { |
80 | CHECK_REQ(req); |
81 | CHECK_HANDLE(req->handle); |
82 | ASSERT(status == 0); |
83 | send_cb_called++; |
84 | } |
85 | |
86 | |
87 | static void ipv6_recv_fail(uv_udp_t* handle, |
88 | ssize_t nread, |
89 | const uv_buf_t* buf, |
90 | const struct sockaddr* addr, |
91 | unsigned flags) { |
92 | ASSERT(0 && "this function should not have been called" ); |
93 | } |
94 | |
95 | |
96 | static void ipv6_recv_ok(uv_udp_t* handle, |
97 | ssize_t nread, |
98 | const uv_buf_t* buf, |
99 | const struct sockaddr* addr, |
100 | unsigned flags) { |
101 | CHECK_HANDLE(handle); |
102 | ASSERT(nread >= 0); |
103 | |
104 | if (nread) |
105 | recv_cb_called++; |
106 | } |
107 | |
108 | |
109 | static void timeout_cb(uv_timer_t* timer) { |
110 | uv_close((uv_handle_t*)&server, close_cb); |
111 | uv_close((uv_handle_t*)&client, close_cb); |
112 | uv_close((uv_handle_t*)&timeout, close_cb); |
113 | } |
114 | |
115 | |
116 | static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { |
117 | struct sockaddr_in6 addr6; |
118 | struct sockaddr_in addr; |
119 | uv_buf_t buf; |
120 | int r; |
121 | |
122 | ASSERT(0 == uv_ip6_addr("::0" , TEST_PORT, &addr6)); |
123 | |
124 | r = uv_udp_init(uv_default_loop(), &server); |
125 | ASSERT(r == 0); |
126 | |
127 | r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags); |
128 | ASSERT(r == 0); |
129 | |
130 | r = uv_udp_recv_start(&server, alloc_cb, recv_cb); |
131 | ASSERT(r == 0); |
132 | |
133 | r = uv_udp_init(uv_default_loop(), &client); |
134 | ASSERT(r == 0); |
135 | |
136 | buf = uv_buf_init("PING" , 4); |
137 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , TEST_PORT, &addr)); |
138 | |
139 | r = uv_udp_send(&req_, |
140 | &client, |
141 | &buf, |
142 | 1, |
143 | (const struct sockaddr*) &addr, |
144 | send_cb); |
145 | ASSERT(r == 0); |
146 | |
147 | r = uv_timer_init(uv_default_loop(), &timeout); |
148 | ASSERT(r == 0); |
149 | |
150 | r = uv_timer_start(&timeout, timeout_cb, 500, 0); |
151 | ASSERT(r == 0); |
152 | |
153 | ASSERT(close_cb_called == 0); |
154 | ASSERT(send_cb_called == 0); |
155 | ASSERT(recv_cb_called == 0); |
156 | |
157 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
158 | |
159 | ASSERT(close_cb_called == 3); |
160 | |
161 | MAKE_VALGRIND_HAPPY(); |
162 | } |
163 | |
164 | |
165 | TEST_IMPL(udp_dual_stack) { |
166 | #if defined(__CYGWIN__) || defined(__MSYS__) |
167 | /* FIXME: Does Cygwin support this? */ |
168 | RETURN_SKIP("FIXME: This test needs more investigation on Cygwin" ); |
169 | #endif |
170 | |
171 | if (!can_ipv6()) |
172 | RETURN_SKIP("IPv6 not supported" ); |
173 | |
174 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
175 | if (!can_ipv6_ipv4_dual()) |
176 | RETURN_SKIP("IPv6-IPv4 dual stack not supported" ); |
177 | #elif defined(__OpenBSD__) |
178 | RETURN_SKIP("IPv6-IPv4 dual stack not supported" ); |
179 | #endif |
180 | |
181 | do_test(ipv6_recv_ok, 0); |
182 | |
183 | ASSERT(recv_cb_called == 1); |
184 | ASSERT(send_cb_called == 1); |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | |
190 | TEST_IMPL(udp_ipv6_only) { |
191 | if (!can_ipv6()) |
192 | RETURN_SKIP("IPv6 not supported" ); |
193 | |
194 | do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY); |
195 | |
196 | ASSERT(recv_cb_called == 0); |
197 | ASSERT(send_cb_called == 1); |
198 | |
199 | return 0; |
200 | } |
201 | |