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 | |
34 | static int send_cb_called = 0; |
35 | static int close_cb_called = 0; |
36 | |
37 | static uv_udp_send_t send_req; |
38 | |
39 | |
40 | static void startup(void) { |
41 | #ifdef _WIN32 |
42 | struct WSAData wsa_data; |
43 | int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); |
44 | ASSERT(r == 0); |
45 | #endif |
46 | } |
47 | |
48 | |
49 | static 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(sock != INVALID_SOCKET); |
55 | #else |
56 | ASSERT(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(r == 0); |
65 | } |
66 | #endif |
67 | |
68 | return sock; |
69 | } |
70 | |
71 | |
72 | static 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(r == 0); |
80 | } |
81 | |
82 | |
83 | static void alloc_cb(uv_handle_t* handle, |
84 | size_t suggested_size, |
85 | uv_buf_t* buf) { |
86 | static char slab[65536]; |
87 | ASSERT(suggested_size <= sizeof(slab)); |
88 | buf->base = slab; |
89 | buf->len = sizeof(slab); |
90 | } |
91 | |
92 | |
93 | static void close_cb(uv_handle_t* handle) { |
94 | ASSERT(handle != NULL); |
95 | close_cb_called++; |
96 | } |
97 | |
98 | |
99 | static 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(addr == NULL); |
113 | return; |
114 | } |
115 | |
116 | ASSERT(flags == 0); |
117 | |
118 | ASSERT(addr != NULL); |
119 | ASSERT(nread == 4); |
120 | ASSERT(memcmp("PING" , buf->base, nread) == 0); |
121 | |
122 | r = uv_udp_recv_stop(handle); |
123 | ASSERT(r == 0); |
124 | |
125 | uv_close((uv_handle_t*) handle, close_cb); |
126 | } |
127 | |
128 | |
129 | static void send_cb(uv_udp_send_t* req, int status) { |
130 | ASSERT(req != NULL); |
131 | ASSERT(status == 0); |
132 | |
133 | send_cb_called++; |
134 | uv_close((uv_handle_t*)req->handle, close_cb); |
135 | } |
136 | |
137 | |
138 | TEST_IMPL(udp_open) { |
139 | struct sockaddr_in addr; |
140 | uv_buf_t buf = uv_buf_init("PING" , 4); |
141 | uv_udp_t client; |
142 | uv_os_sock_t sock; |
143 | int r; |
144 | |
145 | ASSERT(0 == 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(r == 0); |
152 | |
153 | r = uv_udp_open(&client, sock); |
154 | ASSERT(r == 0); |
155 | |
156 | r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); |
157 | ASSERT(r == 0); |
158 | |
159 | r = uv_udp_recv_start(&client, alloc_cb, recv_cb); |
160 | ASSERT(r == 0); |
161 | |
162 | r = uv_udp_send(&send_req, |
163 | &client, |
164 | &buf, |
165 | 1, |
166 | (const struct sockaddr*) &addr, |
167 | send_cb); |
168 | ASSERT(r == 0); |
169 | |
170 | #ifndef _WIN32 |
171 | { |
172 | uv_udp_t client2; |
173 | |
174 | r = uv_udp_init(uv_default_loop(), &client2); |
175 | ASSERT(r == 0); |
176 | |
177 | r = uv_udp_open(&client2, sock); |
178 | ASSERT(r == UV_EEXIST); |
179 | |
180 | uv_close((uv_handle_t*) &client2, NULL); |
181 | } |
182 | #endif /* !_WIN32 */ |
183 | |
184 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
185 | |
186 | ASSERT(send_cb_called == 1); |
187 | ASSERT(close_cb_called == 1); |
188 | |
189 | ASSERT(client.send_queue_size == 0); |
190 | |
191 | MAKE_VALGRIND_HAPPY(); |
192 | return 0; |
193 | } |
194 | |
195 | |
196 | TEST_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(r == 0); |
207 | |
208 | r = uv_udp_open(&client, sock1); |
209 | ASSERT(r == 0); |
210 | |
211 | r = uv_udp_open(&client, sock2); |
212 | ASSERT(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(); |
219 | return 0; |
220 | } |
221 | |
222 | TEST_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(0 == 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(r == 0); |
235 | |
236 | r = uv_udp_init(uv_default_loop(), &client); |
237 | ASSERT(r == 0); |
238 | |
239 | r = uv_udp_open(&client, sock); |
240 | ASSERT(r == 0); |
241 | |
242 | r = uv_udp_recv_start(&client, alloc_cb, recv_cb); |
243 | ASSERT(r == 0); |
244 | |
245 | uv_close((uv_handle_t*) &client, NULL); |
246 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
247 | |
248 | MAKE_VALGRIND_HAPPY(); |
249 | return 0; |
250 | } |
251 | |
252 | TEST_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(0 == 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(r == 0); |
267 | |
268 | r = connect(sock, (const struct sockaddr*) &addr, sizeof(addr)); |
269 | ASSERT(r == 0); |
270 | |
271 | r = uv_udp_open(&client, sock); |
272 | ASSERT(r == 0); |
273 | |
274 | r = uv_udp_init(uv_default_loop(), &server); |
275 | ASSERT(r == 0); |
276 | |
277 | r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); |
278 | ASSERT(r == 0); |
279 | |
280 | r = uv_udp_recv_start(&server, alloc_cb, recv_cb); |
281 | ASSERT(r == 0); |
282 | |
283 | r = uv_udp_send(&send_req, |
284 | &client, |
285 | &buf, |
286 | 1, |
287 | NULL, |
288 | send_cb); |
289 | ASSERT(r == 0); |
290 | |
291 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
292 | |
293 | ASSERT(send_cb_called == 1); |
294 | ASSERT(close_cb_called == 2); |
295 | |
296 | ASSERT(client.send_queue_size == 0); |
297 | |
298 | MAKE_VALGRIND_HAPPY(); |
299 | return 0; |
300 | } |
301 | |
302 | #ifndef _WIN32 |
303 | TEST_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(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(fd >= 0); |
323 | |
324 | unlink(TEST_PIPENAME); |
325 | ASSERT(0 == bind(fd, (const struct sockaddr*)&addr, sizeof addr)); |
326 | ASSERT(0 == listen(fd, 1)); |
327 | |
328 | r = uv_udp_init(loop, &handle); |
329 | ASSERT(r == 0); |
330 | r = uv_udp_open(&handle, fd); |
331 | ASSERT(r == 0); |
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(r == 0); |
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(); |
348 | return 0; |
349 | } |
350 | #endif |
351 | |