-freeing addrinfo
[oweals/gnunet.git] / src / testing / testing_new.c
1 /*
2       This file is part of GNUnet
3       (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file testing/testing_new.c
23  * @brief convenience API for writing testcases for GNUnet
24  *        Many testcases need to start and stop a peer/service
25  *        and this library is supposed to make that easier
26  *        for TESTCASES.  Normal programs should always
27  *        use functions from gnunet_{util,arm}_lib.h.  This API is
28  *        ONLY for writing testcases (or internal use of the testbed).
29  * @author Christian Grothoff
30  *
31  */
32 #include "platform.h"
33 #include "gnunet_disk_lib.h"
34 #include "gnunet_network_lib.h"
35 #include "gnunet_testing_lib-new.h"
36
37
38 /**
39  * Handle for a system on which GNUnet peers are executed;
40  * a system is used for reserving unique paths and ports.
41  */
42 struct GNUNET_TESTING_System
43 {
44   /**
45    * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
46    * SERVICEHOME. 
47    */
48   char *tmppath;
49
50   /**
51    * The hostname of the controller
52    */
53   char *controller;
54
55   /**
56    * Bitmap where each TCP port that has already been reserved for
57    * some GNUnet peer is recorded.  Note that we additionally need to
58    * test if a port is already in use by non-GNUnet components before
59    * assigning it to a peer/service.  If we detect that a port is
60    * already in use, we also mark it in this bitmap.  So all the bits
61    * that are zero merely indicate ports that MIGHT be available for
62    * peers.
63    */
64   uint32_t reserved_tcp_ports[65536 / 32];
65
66   /**
67    * Bitmap where each UDP port that has already been reserved for
68    * some GNUnet peer is recorded.  Note that we additionally need to
69    * test if a port is already in use by non-GNUnet components before
70    * assigning it to a peer/service.  If we detect that a port is
71    * already in use, we also mark it in this bitmap.  So all the bits
72    * that are zero merely indicate ports that MIGHT be available for
73    * peers.
74    */
75   uint32_t reserved_udp_ports[65536 / 32];
76
77   /**
78    * Counter we use to make service home paths unique on this system;
79    * the full path consists of the tmppath and this number.  Each
80    * UNIXPATH for a peer is also modified to include the respective
81    * path counter to ensure uniqueness.  This field is incremented
82    * by one for each configured peer.  Even if peers are destroyed,
83    * we never re-use path counters.
84    */
85   uint32_t path_counter;
86
87   /**
88    * Last used port number
89    */
90   
91 };
92
93
94 /**
95  * Handle for a GNUnet peer controlled by testing.
96  */
97 struct GNUNET_TESTING_Peer
98 {
99
100   /**
101    * Path to the configuration file for this peer.
102    */
103   char *cfgfile;
104
105   /**
106    * Binary to be executed during 'GNUNET_TESTING_peer_start'.
107    * Typically 'gnunet-service-arm' (but can be set to a 
108    * specific service by 'GNUNET_TESTING_service_run' if
109    * necessary).
110    */ 
111   char *main_binary;
112   
113   /**
114    * Handle to the running binary of the service, NULL if the
115    * peer/service is currently not running.
116    */
117   struct GNUNET_OS_Process *main_process;
118
119 };
120
121
122 /**
123  * Lowest port used for GNUnet testing.  Should be high enough to not
124  * conflict with other applications running on the hosts but be low
125  * enough to not conflict with client-ports (typically starting around
126  * 32k).
127  */
128 #define LOW_PORT 12000
129
130
131 /**
132  * Highest port used for GNUnet testing.  Should be low enough to not
133  * conflict with the port range for "local" ports (client apps; see
134  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
135  */
136 #define HIGH_PORT 56000
137
138
139 /**
140  * Create a system handle.  There must only be one system
141  * handle per operating system.
142  *
143  * @param tmppath prefix path to use for all service homes
144  * @param controller hostname of the controlling host, 
145  *        service configurations are modified to allow 
146  *        control connections from this host; can be NULL
147  * @return handle to this system, NULL on error
148  */
149 struct GNUNET_TESTING_System *
150 GNUNET_TESTING_system_create (const char *tmppath,
151                               const char *controller)
152 {
153   struct GNUNET_TESTING_System *system;
154
155   if (NULL == tmppath)
156     return NULL;
157   system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
158   system->tmppath = GNUNET_strdup (tmppath);
159   if (NULL != controller)
160     system->controller = GNUNET_strdup (controller);
161   return system;
162 }
163
164
165 /**
166  * Free system resources.
167  *
168  * @param system system to be freed
169  * @param remove_paths should the 'tmppath' and all subdirectories
170  *        be removed (clean up on shutdown)?
171  */
172 void
173 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
174                                int remove_paths)
175 {
176   GNUNET_assert (NULL != system);
177   if (GNUNET_YES == remove_paths)
178     GNUNET_DISK_directory_remove (system->tmppath);
179   GNUNET_free (system->tmppath);
180   GNUNET_free_non_null (system->controller);
181   GNUNET_free (system);
182 }
183
184
185 /**
186  * Reserve a TCP or UDP port for a peer.
187  *
188  * @param system system to use for reservation tracking
189  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
190  * @return 0 if no free port was available
191  */
192 // static 
193 uint16_t 
194 reserve_port (struct GNUNET_TESTING_System *system,
195               int is_tcp)
196 {
197   struct GNUNET_NETWORK_Handle *socket;
198   struct addrinfo hint;
199   struct addrinfo *ret;
200   uint32_t *port_buckets;
201   char *open_port_str;
202   uint32_t xor_image;
203   uint16_t index;
204   uint16_t open_port;
205   uint8_t pos;
206
207   if (GNUNET_YES == is_tcp)
208   {
209     socket = GNUNET_NETWORK_socket_create (AF_UNSPEC,
210                                            SOCK_STREAM,
211                                            0);
212     port_buckets = system->reserved_tcp_ports;
213   }
214   else
215   {
216     socket = GNUNET_NETWORK_socket_create (AF_UNSPEC,
217                                            SOCK_DGRAM,
218                                            0);
219     port_buckets = system->reserved_udp_ports;
220   }
221   for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
222   {
223     xor_image = (UINT32_MAX ^ port_buckets[index]);
224     if (0 == xor_image)        /* Ports in the bucket are full */
225       continue;
226
227     pos = 0;
228     while (pos < 32)
229     {
230       if (0 == ((xor_image >> pos) & 1U))
231         continue;
232       open_port = (index * 32) + pos;
233       GNUNET_asprintf (&open_port_str, "%u", open_port);
234       hint.ai_family = AF_UNSPEC;       /* IPv4 and IPv6 */
235       hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
236       hint.ai_protocol = 0;
237       hint.ai_addrlen = 0;
238       hint.ai_addr = NULL;
239       hint.ai_canonname = NULL;
240       hint.ai_next = NULL;
241       hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;      /* Wild card address */
242       ret = NULL;
243       GNUNET_assert (0 != getaddrinfo (NULL, open_port_str, &hint, &ret));
244       GNUNET_free (open_port_str);
245       if (GNUNET_OK == GNUNET_NETWORK_socket_bind (socket, ret->ai_addr, ret->ai_addrlen))
246       {
247         freeaddrinfo (ret);
248         return open_port;
249       }
250       freeaddrinfo (ret);
251       /* This port is in use by some other application */
252       port_buckets[index] |= (1U << pos);    
253       pos++;
254     }
255   }
256   return 0;
257 }
258
259
260 /**
261  * Release reservation of a TCP or UDP port for a peer
262  * (used during GNUNET_TESTING_peer_destroy).
263  *
264  * @param system system to use for reservation tracking
265  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
266  * @param port reserved port to release
267  */
268 // static 
269 void
270 release_port (struct GNUNET_TESTING_System *system,
271               int is_tcp,
272               uint16_t port)
273 {
274   GNUNET_break (0);
275 }
276
277
278 /**
279  * Reserve a SERVICEHOME path for a peer.
280  *
281  * @param system system to use for reservation tracking
282  * @return NULL on error, otherwise fresh unique path to use
283  *         as the servicehome for the peer
284  */
285 // static 
286 char *
287 reserve_path (struct GNUNET_TESTING_System *system)
288 {
289   GNUNET_break (0);
290   return NULL;
291 }             
292
293
294 /**
295  * Testing includes a number of pre-created hostkeys for
296  * faster peer startup.  This function can be used to
297  * access the n-th key of those pre-created hostkeys; note
298  * that these keys are ONLY useful for testing and not
299  * secure as the private keys are part of the public 
300  * GNUnet source code.
301  *
302  * This is primarily a helper function used internally
303  * by 'GNUNET_TESTING_peer_configure'.
304  *
305  * @param key_number desired pre-created hostkey to obtain
306  * @param filename where to store the hostkey (file will
307  *        be created, or overwritten if it already exists)
308  * @param id set to the peer's identity (hash of the public
309  *        key; can be NULL
310  * @return GNUNET_SYSERR on error (not enough keys)
311  */
312 int
313 GNUNET_TESTING_hostkey_get (uint32_t key_number,
314                             const char *filename,
315                             struct GNUNET_PeerIdentity *id)
316 {
317   GNUNET_break (0);
318   return GNUNET_SYSERR;
319 }
320
321
322 /**
323  * Create a new configuration using the given configuration
324  * as a template; ports and paths will be modified to select
325  * available ports on the local system.  If we run
326  * out of "*port" numbers, return SYSERR.
327  *
328  * This is primarily a helper function used internally
329  * by 'GNUNET_TESTING_peer_configure'.
330  *
331  * @param system system to use to coordinate resource usage
332  * @param cfg template configuration to update
333  * @return GNUNET_OK on success, GNUNET_SYSERR on error
334  */
335 int
336 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
337                                      struct GNUNET_CONFIGURATION_Handle *cfg)
338 {
339   GNUNET_break (0);
340   return GNUNET_SYSERR;
341 }
342
343
344 /**
345  * Configure a GNUnet peer.  GNUnet must be installed on the local
346  * system and available in the PATH. 
347  *
348  * @param system system to use to coordinate resource usage
349  * @param cfg configuration to use; will be UPDATED (to reflect needed
350  *            changes in port numbers and paths)
351  * @param key_number number of the hostkey to use for the peer
352  * @param id identifier for the daemon, will be set, can be NULL
353  * @param emsg set to error message (set to NULL on success), can be NULL
354  * @return handle to the peer, NULL on error
355  */
356 struct GNUNET_TESTING_Peer *
357 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
358                                struct GNUNET_CONFIGURATION_Handle *cfg,
359                                uint32_t key_number,
360                                struct GNUNET_PeerIdentity *id,
361                                char **emsg)
362 {
363   GNUNET_break (0);
364   return NULL;
365 }
366
367
368 /**
369  * Start the peer. 
370  *
371  * @param peer peer to start
372  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
373  */
374 int
375 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
376 {
377   GNUNET_break (0);
378   return GNUNET_SYSERR;
379 }
380
381
382 /**
383  * Stop the peer. 
384  *
385  * @param peer peer to stop
386  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
387  */
388 int
389 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
390 {
391   GNUNET_break (0);
392   return GNUNET_SYSERR;
393 }
394
395
396 /**
397  * Destroy the peer.  Releases resources locked during peer configuration.
398  * If the peer is still running, it will be stopped AND a warning will be
399  * printed (users of the API should stop the peer explicitly first).
400  *
401  * @param peer peer to destroy
402  */
403 void
404 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
405 {
406   GNUNET_break (0);
407 }
408
409
410
411 /**
412  * Start a single peer and run a test using the testing library.
413  * Starts a peer using the given configuration and then invokes the
414  * given callback.  This function ALSO initializes the scheduler loop
415  * and should thus be called directly from "main".  The testcase
416  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
417  *
418  * @param tmppath path for storing temporary data for the test
419  * @param cfgfilename name of the configuration file to use;
420  *         use NULL to only run with defaults
421  * @param tm main function of the testcase
422  * @param tm_cls closure for 'tm'
423  * @return 0 on success, 1 on error
424  */
425 int
426 GNUNET_TESTING_peer_run (const char *tmppath,
427                          const char *cfgfilename,
428                          GNUNET_TESTING_TestMain tm,
429                          void *tm_cls)
430 {
431   return GNUNET_TESTING_service_run (tmppath, "arm",
432                                      cfgfilename, tm, tm_cls);
433 }
434
435
436
437 /**
438  * Start a single service (no ARM, except of course if the given
439  * service name is 'arm') and run a test using the testing library.
440  * Starts a service using the given configuration and then invokes the
441  * given callback.  This function ALSO initializes the scheduler loop
442  * and should thus be called directly from "main".  The testcase
443  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
444  *
445  * This function is useful if the testcase is for a single service
446  * and if that service doesn't itself depend on other services.
447  *
448  * @param tmppath path for storing temporary data for the test
449  * @param service_name name of the service to run
450  * @param cfgfilename name of the configuration file to use;
451  *         use NULL to only run with defaults
452  * @param tm main function of the testcase
453  * @param tm_cls closure for 'tm'
454  * @return 0 on success, 1 on error
455  */
456 int
457 GNUNET_TESTING_service_run (const char *tmppath,
458                             const char *service_name,
459                             const char *cfgfilename,
460                             GNUNET_TESTING_TestMain tm,
461                             void *tm_cls)
462 {
463   GNUNET_break (0);
464   return 1;
465 }
466
467
468
469 /* end of testing_new.c */