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