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 | static const int server_port = TEST_PORT; |
30 | /* Will be updated right after making the uv_connect_call */ |
31 | static int connect_port = -1; |
32 | |
33 | static int getsocknamecount = 0; |
34 | static int getpeernamecount = 0; |
35 | |
36 | static uv_loop_t* loop; |
37 | static uv_tcp_t tcp; |
38 | static uv_udp_t udp; |
39 | static uv_connect_t connect_req; |
40 | static uv_tcp_t tcpServer; |
41 | static uv_udp_t udpServer; |
42 | static uv_udp_send_t send_req; |
43 | |
44 | |
45 | static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { |
46 | buf->base = malloc(suggested_size); |
47 | buf->len = suggested_size; |
48 | } |
49 | |
50 | |
51 | static void on_close(uv_handle_t* peer) { |
52 | free(peer); |
53 | uv_close((uv_handle_t*)&tcpServer, NULL); |
54 | } |
55 | |
56 | |
57 | static void after_shutdown(uv_shutdown_t* req, int status) { |
58 | uv_close((uv_handle_t*) req->handle, on_close); |
59 | free(req); |
60 | } |
61 | |
62 | |
63 | static void after_read(uv_stream_t* handle, |
64 | ssize_t nread, |
65 | const uv_buf_t* buf) { |
66 | uv_shutdown_t* req; |
67 | int r; |
68 | |
69 | if (buf->base) { |
70 | free(buf->base); |
71 | } |
72 | |
73 | req = (uv_shutdown_t*) malloc(sizeof *req); |
74 | r = uv_shutdown(req, handle, after_shutdown); |
75 | ASSERT(r == 0); |
76 | } |
77 | |
78 | |
79 | static void check_sockname(struct sockaddr* addr, const char* compare_ip, |
80 | int compare_port, const char* context) { |
81 | struct sockaddr_in check_addr = *(struct sockaddr_in*) addr; |
82 | struct sockaddr_in compare_addr; |
83 | char check_ip[17]; |
84 | int r; |
85 | |
86 | ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr)); |
87 | |
88 | /* Both addresses should be ipv4 */ |
89 | ASSERT(check_addr.sin_family == AF_INET); |
90 | ASSERT(compare_addr.sin_family == AF_INET); |
91 | |
92 | /* Check if the ip matches */ |
93 | ASSERT(memcmp(&check_addr.sin_addr, |
94 | &compare_addr.sin_addr, |
95 | sizeof compare_addr.sin_addr) == 0); |
96 | |
97 | /* Check if the port matches. If port == 0 anything goes. */ |
98 | ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port); |
99 | |
100 | r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip); |
101 | ASSERT(r == 0); |
102 | |
103 | printf("%s: %s:%d\n" , context, check_ip, ntohs(check_addr.sin_port)); |
104 | } |
105 | |
106 | |
107 | static void on_connection(uv_stream_t* server, int status) { |
108 | struct sockaddr sockname, peername; |
109 | int namelen; |
110 | uv_tcp_t* handle; |
111 | int r; |
112 | |
113 | if (status != 0) { |
114 | fprintf(stderr, "Connect error %s\n" , uv_err_name(status)); |
115 | } |
116 | ASSERT(status == 0); |
117 | |
118 | handle = malloc(sizeof(*handle)); |
119 | ASSERT(handle != NULL); |
120 | |
121 | r = uv_tcp_init(loop, handle); |
122 | ASSERT(r == 0); |
123 | |
124 | /* associate server with stream */ |
125 | handle->data = server; |
126 | |
127 | r = uv_accept(server, (uv_stream_t*)handle); |
128 | ASSERT(r == 0); |
129 | |
130 | namelen = sizeof sockname; |
131 | r = uv_tcp_getsockname(handle, &sockname, &namelen); |
132 | ASSERT(r == 0); |
133 | check_sockname(&sockname, "127.0.0.1" , server_port, "accepted socket" ); |
134 | getsocknamecount++; |
135 | |
136 | namelen = sizeof peername; |
137 | r = uv_tcp_getpeername(handle, &peername, &namelen); |
138 | ASSERT(r == 0); |
139 | check_sockname(&peername, "127.0.0.1" , connect_port, "accepted socket peer" ); |
140 | getpeernamecount++; |
141 | |
142 | r = uv_read_start((uv_stream_t*)handle, alloc, after_read); |
143 | ASSERT(r == 0); |
144 | } |
145 | |
146 | |
147 | static void on_connect(uv_connect_t* req, int status) { |
148 | struct sockaddr sockname, peername; |
149 | int r, namelen; |
150 | |
151 | ASSERT(status == 0); |
152 | |
153 | namelen = sizeof sockname; |
154 | r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen); |
155 | ASSERT(r == 0); |
156 | check_sockname(&sockname, "127.0.0.1" , 0, "connected socket" ); |
157 | getsocknamecount++; |
158 | |
159 | namelen = sizeof peername; |
160 | r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen); |
161 | ASSERT(r == 0); |
162 | check_sockname(&peername, "127.0.0.1" , server_port, "connected socket peer" ); |
163 | getpeernamecount++; |
164 | |
165 | uv_close((uv_handle_t*)&tcp, NULL); |
166 | } |
167 | |
168 | |
169 | static int tcp_listener(void) { |
170 | struct sockaddr_in addr; |
171 | struct sockaddr sockname, peername; |
172 | int namelen; |
173 | int r; |
174 | |
175 | ASSERT(0 == uv_ip4_addr("0.0.0.0" , server_port, &addr)); |
176 | |
177 | r = uv_tcp_init(loop, &tcpServer); |
178 | if (r) { |
179 | fprintf(stderr, "Socket creation error\n" ); |
180 | return 1; |
181 | } |
182 | |
183 | r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0); |
184 | if (r) { |
185 | fprintf(stderr, "Bind error\n" ); |
186 | return 1; |
187 | } |
188 | |
189 | r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection); |
190 | if (r) { |
191 | fprintf(stderr, "Listen error\n" ); |
192 | return 1; |
193 | } |
194 | |
195 | memset(&sockname, -1, sizeof sockname); |
196 | namelen = sizeof sockname; |
197 | r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen); |
198 | ASSERT(r == 0); |
199 | check_sockname(&sockname, "0.0.0.0" , server_port, "server socket" ); |
200 | getsocknamecount++; |
201 | |
202 | namelen = sizeof sockname; |
203 | r = uv_tcp_getpeername(&tcpServer, &peername, &namelen); |
204 | ASSERT(r == UV_ENOTCONN); |
205 | getpeernamecount++; |
206 | |
207 | return 0; |
208 | } |
209 | |
210 | |
211 | static void tcp_connector(void) { |
212 | struct sockaddr_in server_addr; |
213 | struct sockaddr sockname; |
214 | int r, namelen; |
215 | |
216 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , server_port, &server_addr)); |
217 | |
218 | r = uv_tcp_init(loop, &tcp); |
219 | tcp.data = &connect_req; |
220 | ASSERT(!r); |
221 | |
222 | r = uv_tcp_connect(&connect_req, |
223 | &tcp, |
224 | (const struct sockaddr*) &server_addr, |
225 | on_connect); |
226 | ASSERT(!r); |
227 | |
228 | /* Fetch the actual port used by the connecting socket. */ |
229 | namelen = sizeof sockname; |
230 | r = uv_tcp_getsockname(&tcp, &sockname, &namelen); |
231 | ASSERT(!r); |
232 | ASSERT(sockname.sa_family == AF_INET); |
233 | connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port); |
234 | ASSERT(connect_port > 0); |
235 | } |
236 | |
237 | |
238 | static void udp_recv(uv_udp_t* handle, |
239 | ssize_t nread, |
240 | const uv_buf_t* buf, |
241 | const struct sockaddr* addr, |
242 | unsigned flags) { |
243 | struct sockaddr sockname; |
244 | int namelen; |
245 | int r; |
246 | |
247 | ASSERT(nread >= 0); |
248 | free(buf->base); |
249 | |
250 | if (nread == 0) { |
251 | return; |
252 | } |
253 | |
254 | memset(&sockname, -1, sizeof sockname); |
255 | namelen = sizeof(sockname); |
256 | r = uv_udp_getsockname(&udp, &sockname, &namelen); |
257 | ASSERT(r == 0); |
258 | check_sockname(&sockname, "0.0.0.0" , 0, "udp receiving socket" ); |
259 | getsocknamecount++; |
260 | |
261 | uv_close((uv_handle_t*) &udp, NULL); |
262 | uv_close((uv_handle_t*) handle, NULL); |
263 | } |
264 | |
265 | |
266 | static void udp_send(uv_udp_send_t* req, int status) { |
267 | |
268 | } |
269 | |
270 | |
271 | static int udp_listener(void) { |
272 | struct sockaddr_in addr; |
273 | struct sockaddr sockname; |
274 | int namelen; |
275 | int r; |
276 | |
277 | ASSERT(0 == uv_ip4_addr("0.0.0.0" , server_port, &addr)); |
278 | |
279 | r = uv_udp_init(loop, &udpServer); |
280 | if (r) { |
281 | fprintf(stderr, "Socket creation error\n" ); |
282 | return 1; |
283 | } |
284 | |
285 | r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0); |
286 | if (r) { |
287 | fprintf(stderr, "Bind error\n" ); |
288 | return 1; |
289 | } |
290 | |
291 | memset(&sockname, -1, sizeof sockname); |
292 | namelen = sizeof sockname; |
293 | r = uv_udp_getsockname(&udpServer, &sockname, &namelen); |
294 | ASSERT(r == 0); |
295 | check_sockname(&sockname, "0.0.0.0" , server_port, "udp listener socket" ); |
296 | getsocknamecount++; |
297 | |
298 | r = uv_udp_recv_start(&udpServer, alloc, udp_recv); |
299 | ASSERT(r == 0); |
300 | |
301 | return 0; |
302 | } |
303 | |
304 | |
305 | static void udp_sender(void) { |
306 | struct sockaddr_in server_addr; |
307 | uv_buf_t buf; |
308 | int r; |
309 | |
310 | r = uv_udp_init(loop, &udp); |
311 | ASSERT(!r); |
312 | |
313 | buf = uv_buf_init("PING" , 4); |
314 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , server_port, &server_addr)); |
315 | |
316 | r = uv_udp_send(&send_req, |
317 | &udp, |
318 | &buf, |
319 | 1, |
320 | (const struct sockaddr*) &server_addr, |
321 | udp_send); |
322 | ASSERT(!r); |
323 | } |
324 | |
325 | |
326 | TEST_IMPL(getsockname_tcp) { |
327 | loop = uv_default_loop(); |
328 | |
329 | if (tcp_listener()) |
330 | return 1; |
331 | |
332 | tcp_connector(); |
333 | |
334 | uv_run(loop, UV_RUN_DEFAULT); |
335 | |
336 | ASSERT(getsocknamecount == 3); |
337 | ASSERT(getpeernamecount == 3); |
338 | |
339 | MAKE_VALGRIND_HAPPY(); |
340 | return 0; |
341 | } |
342 | |
343 | |
344 | TEST_IMPL(getsockname_udp) { |
345 | loop = uv_default_loop(); |
346 | |
347 | if (udp_listener()) |
348 | return 1; |
349 | |
350 | udp_sender(); |
351 | |
352 | uv_run(loop, UV_RUN_DEFAULT); |
353 | |
354 | ASSERT(getsocknamecount == 2); |
355 | |
356 | ASSERT(udp.send_queue_size == 0); |
357 | ASSERT(udpServer.send_queue_size == 0); |
358 | |
359 | MAKE_VALGRIND_HAPPY(); |
360 | return 0; |
361 | } |
362 | |