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