libuv-svace-build
218 строк · 5.6 Кб
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
30#define CHECK_HANDLE(handle) \
31ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0)
32
33#if defined(__APPLE__) || \
34defined(_AIX) || \
35defined(__MVS__) || \
36defined(__NetBSD__) || \
37defined(__OpenBSD__)
38#define MULTICAST_ADDR "ff02::1%lo0"
39#define INTERFACE_ADDR "::1%lo0"
40#else
41#define MULTICAST_ADDR "ff02::1"
42#define INTERFACE_ADDR NULL
43#endif
44
45static uv_udp_t server;
46static uv_udp_t client;
47static uv_udp_send_t req;
48static uv_udp_send_t req_ss;
49
50static int cl_recv_cb_called;
51
52static int sv_send_cb_called;
53
54static int close_cb_called;
55
56static void alloc_cb(uv_handle_t* handle,
57size_t suggested_size,
58uv_buf_t* buf) {
59static char slab[65536];
60CHECK_HANDLE(handle);
61ASSERT_LE(suggested_size, sizeof(slab));
62buf->base = slab;
63buf->len = sizeof(slab);
64}
65
66
67static void close_cb(uv_handle_t* handle) {
68CHECK_HANDLE(handle);
69close_cb_called++;
70}
71
72
73static void sv_send_cb(uv_udp_send_t* req, int status) {
74ASSERT_NOT_NULL(req);
75ASSERT_OK(status);
76CHECK_HANDLE(req->handle);
77
78sv_send_cb_called++;
79
80if (sv_send_cb_called == 2)
81uv_close((uv_handle_t*) req->handle, close_cb);
82}
83
84
85static int do_send(uv_udp_send_t* send_req) {
86uv_buf_t buf;
87struct sockaddr_in6 addr;
88
89buf = uv_buf_init("PING", 4);
90
91ASSERT_OK(uv_ip6_addr(MULTICAST_ADDR, TEST_PORT, &addr));
92
93/* client sends "PING" */
94return uv_udp_send(send_req,
95&client,
96&buf,
971,
98(const struct sockaddr*) &addr,
99sv_send_cb);
100}
101
102
103static void cl_recv_cb(uv_udp_t* handle,
104ssize_t nread,
105const uv_buf_t* buf,
106const struct sockaddr* addr,
107unsigned flags) {
108CHECK_HANDLE(handle);
109ASSERT_OK(flags);
110
111if (nread < 0) {
112ASSERT(0 && "unexpected error");
113}
114
115if (nread == 0) {
116/* Returning unused buffer. Don't count towards cl_recv_cb_called */
117ASSERT_NULL(addr);
118return;
119}
120
121ASSERT_NOT_NULL(addr);
122ASSERT_EQ(4, nread);
123ASSERT(!memcmp("PING", buf->base, nread));
124
125cl_recv_cb_called++;
126
127if (cl_recv_cb_called == 2) {
128/* we are done with the server handle, we can close it */
129uv_close((uv_handle_t*) &server, close_cb);
130} else {
131int r;
132char source_addr[64];
133
134r = uv_ip6_name((const struct sockaddr_in6*)addr, source_addr, sizeof(source_addr));
135ASSERT_OK(r);
136
137r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_LEAVE_GROUP);
138ASSERT_OK(r);
139
140r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, source_addr, UV_JOIN_GROUP);
141ASSERT_OK(r);
142
143r = do_send(&req_ss);
144ASSERT_OK(r);
145}
146}
147
148
149static int can_ipv6_external(void) {
150uv_interface_address_t* addr;
151int supported;
152int count;
153int i;
154
155if (uv_interface_addresses(&addr, &count))
156return 0; /* Assume no IPv6 support on failure. */
157
158supported = 0;
159for (i = 0; supported == 0 && i < count; i += 1)
160supported = (AF_INET6 == addr[i].address.address6.sin6_family &&
161!addr[i].is_internal);
162
163uv_free_interface_addresses(addr, count);
164return supported;
165}
166
167
168TEST_IMPL(udp_multicast_join6) {
169int r;
170struct sockaddr_in6 addr;
171
172if (!can_ipv6_external())
173RETURN_SKIP("No external IPv6 interface available");
174
175ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr));
176
177r = uv_udp_init(uv_default_loop(), &server);
178ASSERT_OK(r);
179
180r = uv_udp_init(uv_default_loop(), &client);
181ASSERT_OK(r);
182
183/* bind to the desired port */
184r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
185ASSERT_OK(r);
186
187r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_JOIN_GROUP);
188if (r == UV_ENODEV) {
189MAKE_VALGRIND_HAPPY(uv_default_loop());
190RETURN_SKIP("No ipv6 multicast route");
191}
192
193ASSERT_OK(r);
194
195/* TODO(gengjiawen): Fix test on QEMU. */
196#if defined(__QEMU__)
197RETURN_SKIP("Test does not currently work in QEMU");
198#endif
199r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb);
200ASSERT_OK(r);
201
202r = do_send(&req);
203ASSERT_OK(r);
204
205ASSERT_OK(close_cb_called);
206ASSERT_OK(cl_recv_cb_called);
207ASSERT_OK(sv_send_cb_called);
208
209/* run the loop till all events are processed */
210uv_run(uv_default_loop(), UV_RUN_DEFAULT);
211
212ASSERT_EQ(2, cl_recv_cb_called);
213ASSERT_EQ(2, sv_send_cb_called);
214ASSERT_EQ(2, close_cb_called);
215
216MAKE_VALGRIND_HAPPY(uv_default_loop());
217return 0;
218}
219