aboutsummaryrefslogtreecommitdiff
path: root/src/service/nat/test_stun.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/nat/test_stun.c')
-rw-r--r--src/service/nat/test_stun.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/service/nat/test_stun.c b/src/service/nat/test_stun.c
new file mode 100644
index 000000000..75eb877b3
--- /dev/null
+++ b/src/service/nat/test_stun.c
@@ -0,0 +1,313 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * Testcase for STUN server resolution
23 *
24 * @file nat/test_stun.c
25 * @brief Testcase for STUN library
26 * @author Bruno Souza Cabral
27 * @author Christian Grothoff
28 */
29
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_program_lib.h"
34#include "gnunet_scheduler_lib.h"
35#include "gnunet_nat_lib.h"
36
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "test-stun", __VA_ARGS__)
39
40/**
41 * Time to wait before stopping NAT, in seconds
42 */
43#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
44
45
46/**
47 * The port the test service is running on (default 7895)
48 */
49static unsigned long port = 7895;
50
51static int ret = 1;
52
53static const char *stun_server = "stun.gnunet.org";
54
55static int stun_port = 3478;
56
57/**
58 * The listen socket of the service for IPv4
59 */
60static struct GNUNET_NETWORK_Handle *lsock4;
61
62/**
63 * The listen task ID for IPv4
64 */
65static struct GNUNET_SCHEDULER_Task *ltask4;
66
67/**
68 * Handle for the STUN request.
69 */
70static struct GNUNET_NAT_STUN_Handle *rh;
71
72
73static void
74print_answer (struct sockaddr_in*answer)
75{
76 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
77 "External IP is: %s , with port %d\n",
78 inet_ntoa (answer->sin_addr),
79 ntohs (answer->sin_port));
80}
81
82
83/**
84 * Function that terminates the test.
85 */
86static void
87stop ()
88{
89 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
90 "Stopping NAT and quitting...\n");
91 if (NULL != ltask4)
92 {
93 GNUNET_SCHEDULER_cancel (ltask4);
94 ltask4 = NULL;
95 }
96 if (NULL != lsock4)
97 {
98 GNUNET_NETWORK_socket_close (lsock4);
99 lsock4 = NULL;
100 }
101 if (NULL != rh)
102 {
103 GNUNET_NAT_stun_make_request_cancel (rh);
104 rh = NULL;
105 }
106}
107
108
109/**
110 * Activity on our incoming socket. Read data from the
111 * incoming connection.
112 *
113 * @param cls
114 */
115static void
116do_udp_read (void *cls)
117{
118 // struct GNUNET_NAT_Test *tst = cls;
119 unsigned char reply_buf[1024];
120 ssize_t rlen;
121 struct sockaddr_in answer;
122 const struct GNUNET_SCHEDULER_TaskContext *tc;
123
124 ltask4 = NULL;
125 tc = GNUNET_SCHEDULER_get_task_context ();
126 if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) ||
127 (! GNUNET_NETWORK_fdset_isset (tc->read_ready,
128 lsock4)))
129 {
130 fprintf (stderr,
131 "Timeout waiting for STUN response\n");
132 stop ();
133 }
134 rlen = GNUNET_NETWORK_socket_recv (lsock4,
135 reply_buf,
136 sizeof(reply_buf));
137 memset (&answer,
138 0,
139 sizeof(struct sockaddr_in));
140 if (GNUNET_OK !=
141 GNUNET_NAT_stun_handle_packet (reply_buf,
142 rlen,
143 &answer))
144 {
145 fprintf (stderr,
146 "Unexpected UDP packet, trying to read more\n");
147 ltask4 = GNUNET_SCHEDULER_add_read_net (TIMEOUT,
148 lsock4,
149 &do_udp_read, NULL);
150 return;
151 }
152 ret = 0;
153 print_answer (&answer);
154 stop ();
155}
156
157
158/**
159 * Create an IPv4 listen socket bound to our port.
160 *
161 * @return NULL on error
162 */
163static struct GNUNET_NETWORK_Handle *
164bind_v4 ()
165{
166 struct GNUNET_NETWORK_Handle *ls;
167 struct sockaddr_in sa4;
168 int eno;
169
170 memset (&sa4, 0, sizeof(sa4));
171 sa4.sin_family = AF_INET;
172 sa4.sin_port = htons (port);
173#if HAVE_SOCKADDR_IN_SIN_LEN
174 sa4.sin_len = sizeof(sa4);
175#endif
176 ls = GNUNET_NETWORK_socket_create (AF_INET,
177 SOCK_DGRAM,
178 0);
179 if (NULL == ls)
180 return NULL;
181 if (GNUNET_OK !=
182 GNUNET_NETWORK_socket_bind (ls,
183 (const struct sockaddr *) &sa4,
184 sizeof(sa4)))
185 {
186 eno = errno;
187 GNUNET_NETWORK_socket_close (ls);
188 errno = eno;
189 return NULL;
190 }
191 return ls;
192}
193
194
195/**
196 * Function called with the result of the STUN request transmission attempt.
197 *
198 * @param cls unused
199 * @param error status code from STUN
200 */
201static void
202request_callback (void *cls,
203 enum GNUNET_NAT_StatusCode error)
204{
205 rh = NULL;
206 if (GNUNET_NAT_ERROR_SUCCESS == error)
207 {
208 /* all good, start to receive */
209 ltask4 = GNUNET_SCHEDULER_add_read_net (TIMEOUT,
210 lsock4,
211 &do_udp_read,
212 NULL);
213 return;
214 }
215 if (error == GNUNET_NAT_ERROR_NOT_ONLINE)
216 {
217 ret = 77; /* report 'skip' */
218 fprintf (stderr,
219 "System is offline, cannot test STUN request.\n");
220 }
221 else
222 {
223 ret = error;
224 }
225 stop ();
226}
227
228
229/**
230 * Main function run with scheduler.
231 */
232static void
233run (void *cls,
234 char *const *args,
235 const char *cfgfile,
236 const struct GNUNET_CONFIGURATION_Handle *cfg)
237{
238 // Lets create the socket
239 lsock4 = bind_v4 ();
240 if (NULL == lsock4)
241 {
242 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
243 "bind");
244 GNUNET_SCHEDULER_shutdown ();
245 return;
246 }
247 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
248 "Service listens on port %u\n",
249 (unsigned int) port);
250 rh = GNUNET_NAT_stun_make_request (stun_server,
251 stun_port,
252 lsock4,
253 &request_callback, NULL);
254 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
255 &stop, NULL);
256}
257
258
259int
260main (int argc, char *const argv[])
261{
262 struct GNUNET_GETOPT_CommandLineOption options[] = {
263 GNUNET_GETOPT_OPTION_END
264 };
265 char *const argv_prog[] = {
266 "test-stun",
267 "-c",
268 "test_stun.conf",
269 NULL
270 };
271 char *fn;
272 struct GNUNET_OS_Process *proc;
273
274 GNUNET_log_setup ("test-stun",
275 "WARNING",
276 NULL);
277
278 /* Lets start resolver */
279 fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
280 proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
281 | GNUNET_OS_USE_PIPE_CONTROL,
282 NULL, NULL, NULL,
283 fn,
284 "gnunet-service-resolver",
285 "-c", "test_stun.conf", NULL);
286
287 if (NULL == proc)
288 {
289 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
290 "This test was unable to start gnunet-service-resolver, and it is required to run ...\n");
291 exit (1);
292 }
293
294 GNUNET_PROGRAM_run (3, argv_prog,
295 "test-stun", "nohelp",
296 options,
297 &run, NULL);
298
299 /* Now kill the resolver */
300 if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
301 {
302 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
303 }
304 GNUNET_OS_process_wait (proc);
305 GNUNET_OS_process_destroy (proc);
306 proc = NULL;
307 GNUNET_free (fn);
308
309 return ret;
310}
311
312
313/* end of test_stun.c */