2f4a75a189a9488b0f8ee9b47e8d38b66531458e
[oweals/gnunet.git] / src / testing / testing.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.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_util_lib.h"
34 #include "gnunet_testing_lib-new.h"
35
36 #define LOG(kind,...)                                           \
37   GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
38
39
40 /**
41  * We need pipe control only on WINDOWS
42  */
43 #if WINDOWS
44 #define PIPE_CONTROL GNUNET_YES
45 #else
46 #define PIPE_CONTROL GNUNET_NO
47 #endif
48
49
50 /**
51  * Lowest port used for GNUnet testing.  Should be high enough to not
52  * conflict with other applications running on the hosts but be low
53  * enough to not conflict with client-ports (typically starting around
54  * 32k).
55  */
56 #define LOW_PORT 12000
57
58 /**
59  * Highest port used for GNUnet testing.  Should be low enough to not
60  * conflict with the port range for "local" ports (client apps; see
61  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
62  */
63 #define HIGH_PORT 56000
64
65
66 /**
67  * Handle for a system on which GNUnet peers are executed;
68  * a system is used for reserving unique paths and ports.
69  */
70 struct GNUNET_TESTING_System
71 {
72   /**
73    * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
74    * SERVICEHOME.    */
75   char *tmppath;
76
77   /**
78    * The hostname of the controller
79    */
80   char *controller;
81
82   /**
83    * our hostname
84    */
85   char *hostname;
86
87   /**
88    * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
89    */
90   char *hostkeys_data;
91
92   /**
93    * memory map for 'hostkeys_data'.
94    */
95   struct GNUNET_DISK_MapHandle *map;
96
97   /**
98    * File descriptor for the map.
99    */
100   struct GNUNET_DISK_FileHandle *map_fd;
101
102   /**
103    * Bitmap where each TCP port that has already been reserved for
104    * some GNUnet peer is recorded.  Note that we additionally need to
105    * test if a port is already in use by non-GNUnet components before
106    * assigning it to a peer/service.  If we detect that a port is
107    * already in use, we also mark it in this bitmap.  So all the bits
108    * that are zero merely indicate ports that MIGHT be available for
109    * peers.
110    */
111   uint32_t reserved_tcp_ports[65536 / 32];
112
113   /**
114    * Bitmap where each UDP port that has already been reserved for
115    * some GNUnet peer is recorded.  Note that we additionally need to
116    * test if a port is already in use by non-GNUnet components before
117    * assigning it to a peer/service.  If we detect that a port is
118    * already in use, we also mark it in this bitmap.  So all the bits
119    * that are zero merely indicate ports that MIGHT be available for
120    * peers.
121    */
122   uint32_t reserved_udp_ports[65536 / 32];
123
124   /**
125    * Counter we use to make service home paths unique on this system;
126    * the full path consists of the tmppath and this number.  Each
127    * UNIXPATH for a peer is also modified to include the respective
128    * path counter to ensure uniqueness.  This field is incremented
129    * by one for each configured peer.  Even if peers are destroyed,
130    * we never re-use path counters.
131    */
132   uint32_t path_counter;  
133
134   /**
135    * The number of hostkeys
136    */
137   uint32_t total_hostkeys;
138
139   /**
140    * Lowest port we are allowed to use.
141    */
142   uint16_t lowport;
143
144   /**
145    * Highest port we are allowed to use.
146    */
147   uint16_t highport;
148 };
149
150
151 /**
152  * Handle for a GNUnet peer controlled by testing.
153  */
154 struct GNUNET_TESTING_Peer
155 {
156   /**
157    * The TESTING system associated with this peer
158    */
159   struct GNUNET_TESTING_System *system;
160
161   /**
162    * Path to the configuration file for this peer.
163    */
164   char *cfgfile;
165
166   /**
167    * Binary to be executed during 'GNUNET_TESTING_peer_start'.
168    * Typically 'gnunet-service-arm' (but can be set to a 
169    * specific service by 'GNUNET_TESTING_service_run' if
170    * necessary).
171    */ 
172   char *main_binary;
173   char *args;
174   
175   /**
176    * Handle to the running binary of the service, NULL if the
177    * peer/service is currently not running.
178    */
179   struct GNUNET_OS_Process *main_process;
180
181   /**
182    * The keynumber of this peer's hostkey
183    */
184   uint32_t key_number;
185 };
186
187
188 /**
189  * Testing includes a number of pre-created hostkeys for faster peer
190  * startup. This function loads such keys into memory from a file.
191  *
192  * @param system the testing system handle
193  * @return GNUNET_OK on success; GNUNET_SYSERR on error
194  */
195 static int
196 hostkeys_load (struct GNUNET_TESTING_System *system)
197 {
198   uint64_t fs; 
199   char *data_dir;
200   char *filename;
201   
202   GNUNET_assert (NULL == system->hostkeys_data);
203   data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
204   GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
205   GNUNET_free (data_dir);  
206
207   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
208   {
209     LOG (GNUNET_ERROR_TYPE_ERROR,
210          _("Hostkeys file not found: %s\n"), filename);
211     GNUNET_free (filename);
212     return GNUNET_SYSERR;
213   }
214   /* Check hostkey file size, read entire thing into memory */
215   if (GNUNET_OK != 
216       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
217     fs = 0;
218   if (0 == fs)
219   {
220     GNUNET_free (filename);
221     return GNUNET_SYSERR;       /* File is empty */
222   }
223   if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
224   {
225     LOG (GNUNET_ERROR_TYPE_ERROR,
226          _("Incorrect hostkey file format: %s\n"), filename);
227     GNUNET_free (filename);
228     return GNUNET_SYSERR;
229   }
230   system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
231                                          GNUNET_DISK_PERM_NONE);
232   if (NULL == system->map_fd)
233   {
234     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
235     GNUNET_free (filename);
236     return GNUNET_SYSERR;
237   }
238   system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
239   system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
240                                                 &system->map,
241                                                 GNUNET_DISK_MAP_TYPE_READ,
242                                                 fs);
243   GNUNET_free (filename);
244   return GNUNET_OK;
245 }
246
247
248 /**
249  * Function to remove the loaded hostkeys
250  *
251  * @param system the testing system handle
252  */
253 static void
254 hostkeys_unload (struct GNUNET_TESTING_System *system)
255 {
256   GNUNET_break (NULL != system->hostkeys_data);
257   system->hostkeys_data = NULL;
258   GNUNET_DISK_file_unmap (system->map);
259   system->map = NULL;
260   GNUNET_DISK_file_close (system->map_fd);
261   system->map_fd = NULL;
262   system->hostkeys_data = NULL;
263   system->total_hostkeys = 0;
264 }
265
266
267 /**
268  * Create a system handle.  There must only be one system
269  * handle per operating system.
270  *
271  * @param testdir only the directory name without any path. This is used for
272  *          all service homes; the directory will be created in a temporary
273  *          location depending on the underlying OS
274  * @param controller hostname of the controlling host, 
275  *        service configurations are modified to allow 
276  *        control connections from this host; can be NULL
277  * @param hostname the hostname of the system we are using for testing; NULL for
278  *          localhost
279  * @param lowport lowest port number this system is allowed to allocate (inclusive)
280  * @param highport highest port number this system is allowed to allocate (exclusive)
281  * @return handle to this system, NULL on error
282  */
283 struct GNUNET_TESTING_System *
284 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
285                                              const char *controller,
286                                              const char *hostname,
287                                              uint16_t lowport,
288                                              uint16_t highport)
289 {
290   struct GNUNET_TESTING_System *system;
291
292   GNUNET_assert (NULL != testdir);
293   system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
294   system->tmppath = GNUNET_DISK_mkdtemp (testdir);
295   system->lowport = lowport;
296   system->highport = highport;
297   if (NULL == system->tmppath)
298   {
299     GNUNET_free (system);
300     return NULL;
301   }
302   if (NULL != controller)
303     system->controller = GNUNET_strdup (controller);
304   if (NULL != hostname)
305     system->hostname = GNUNET_strdup (hostname);
306   if (GNUNET_OK != hostkeys_load (system))
307   {
308     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
309     return NULL;
310   }
311   return system;
312 }
313
314
315 /**
316  * Create a system handle.  There must only be one system handle per operating
317  * system.  Uses a default range for allowed ports.  Ports are still tested for
318  * availability.
319  *
320  * @param testdir only the directory name without any path. This is used for all
321  *          service homes; the directory will be created in a temporary location
322  *          depending on the underlying OS
323  * @param controller hostname of the controlling host, service configurations
324  *        are modified to allow control connections from this host; can be NULL
325  * @param hostname the hostname of the system we are using for testing; NULL for
326  *          localhost
327  * @return handle to this system, NULL on error
328  */
329 struct GNUNET_TESTING_System *
330 GNUNET_TESTING_system_create (const char *testdir,
331                               const char *controller,
332                               const char *hostname)
333 {
334   return GNUNET_TESTING_system_create_with_portrange (testdir,
335                                                       controller,
336                                                       hostname,
337                                                       LOW_PORT,
338                                                       HIGH_PORT);
339 }
340
341
342 /**
343  * Free system resources.
344  *
345  * @param system system to be freed
346  * @param remove_paths should the 'testdir' and all subdirectories
347  *        be removed (clean up on shutdown)?
348  */
349 void
350 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
351                                int remove_paths)
352 {
353   if (NULL != system->hostkeys_data)
354     hostkeys_unload (system);
355   if (GNUNET_YES == remove_paths)
356     GNUNET_DISK_directory_remove (system->tmppath);
357   GNUNET_free (system->tmppath);
358   GNUNET_free_non_null (system->controller);
359   GNUNET_free_non_null (system->hostname);
360   GNUNET_free (system);
361 }
362
363
364 /**
365  * Reserve a TCP or UDP port for a peer.
366  *
367  * @param system system to use for reservation tracking
368  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
369  * @return 0 if no free port was available
370  */
371 uint16_t 
372 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
373                              int is_tcp)
374 {
375   struct GNUNET_NETWORK_Handle *socket;
376   struct addrinfo hint;
377   struct addrinfo *ret;
378   struct addrinfo *ai;
379   uint32_t *port_buckets;
380   char *open_port_str;
381   int bind_status;
382   uint32_t xor_image;
383   uint16_t index;
384   uint16_t open_port;
385   uint16_t pos;
386
387   /*
388   FIXME: Instead of using getaddrinfo we should try to determine the port
389          status by the following heurestics.
390   
391          On systems which support both IPv4 and IPv6, only ports open on both
392          address families are considered open.
393          On system with either IPv4 or IPv6. A port is considered open if it's
394          open in the respective address family
395   */
396   hint.ai_family = AF_UNSPEC;   /* IPv4 and IPv6 */
397   hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
398   hint.ai_protocol = 0;
399   hint.ai_addrlen = 0;
400   hint.ai_addr = NULL;
401   hint.ai_canonname = NULL;
402   hint.ai_next = NULL;
403   hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;  /* Wild card address */
404   port_buckets = (GNUNET_YES == is_tcp) ?
405     system->reserved_tcp_ports : system->reserved_udp_ports;
406   for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
407   {
408     xor_image = (UINT32_MAX ^ port_buckets[index]);
409     if (0 == xor_image)        /* Ports in the bucket are full */
410       continue;
411     pos = system->lowport % 32;
412     while (pos < 32)
413     {
414       if (0 == ((xor_image >> pos) & 1U))
415       {
416         pos++;
417         continue;
418       }
419       open_port = (index * 32) + pos;
420       if (open_port >= system->highport)
421         return 0;
422       GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
423       ret = NULL;
424       GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
425       GNUNET_free (open_port_str);
426       bind_status = GNUNET_NO;
427       for (ai = ret; NULL != ai; ai = ai->ai_next)
428       {
429         socket = GNUNET_NETWORK_socket_create (ai->ai_family,
430                                                (GNUNET_YES == is_tcp) ?
431                                                SOCK_STREAM : SOCK_DGRAM,
432                                                0);
433         if (NULL == socket)
434           continue;
435         bind_status = GNUNET_NETWORK_socket_bind (socket,
436                                                   ai->ai_addr,
437                                                   ai->ai_addrlen);
438         GNUNET_NETWORK_socket_close (socket);
439         if (GNUNET_OK != bind_status)
440           break;
441       }
442       port_buckets[index] |= (1U << pos); /* Set the port bit */
443       freeaddrinfo (ret);
444       if (GNUNET_OK == bind_status)
445       {
446         LOG (GNUNET_ERROR_TYPE_DEBUG,
447              "Found a free port %u\n", (unsigned int) open_port);
448         return open_port;
449       }
450       pos++;
451     }
452   }
453   return 0;
454 }
455
456
457 /**
458  * Release reservation of a TCP or UDP port for a peer
459  * (used during GNUNET_TESTING_peer_destroy).
460  *
461  * @param system system to use for reservation tracking
462  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
463  * @param port reserved port to release
464  */
465 void
466 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
467                              int is_tcp,
468                              uint16_t port)
469 {
470   uint32_t *port_buckets;
471   uint16_t bucket;
472   uint16_t pos;
473
474   port_buckets = (GNUNET_YES == is_tcp) ?
475     system->reserved_tcp_ports : system->reserved_udp_ports;
476   bucket = port / 32;
477   pos = port % 32;
478   LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
479   if (0 == (port_buckets[bucket] & (1U << pos)))
480   {
481     GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
482     return;
483   }
484   port_buckets[bucket] &= ~(1U << pos);
485 }
486
487
488 /**
489  * Reserve a SERVICEHOME path for a peer.
490  *
491  * @param system system to use for reservation tracking
492  * @return NULL on error, otherwise fresh unique path to use
493  *         as the servicehome for the peer; must be freed by the caller
494  */
495 // static 
496 char *
497 reserve_path (struct GNUNET_TESTING_System *system)
498 {
499   char *reserved_path;
500
501   GNUNET_asprintf (&reserved_path,
502                    "%s/%u", system->tmppath, system->path_counter++);
503   return reserved_path;
504 }             
505
506
507 /**
508  * Testing includes a number of pre-created hostkeys for
509  * faster peer startup.  This function can be used to
510  * access the n-th key of those pre-created hostkeys; note
511  * that these keys are ONLY useful for testing and not
512  * secure as the private keys are part of the public 
513  * GNUnet source code.
514  *
515  * This is primarily a helper function used internally
516  * by 'GNUNET_TESTING_peer_configure'.
517  *
518  * @param system the testing system handle
519  * @param key_number desired pre-created hostkey to obtain
520  * @param id set to the peer's identity (hash of the public
521  *        key; if NULL, GNUNET_SYSERR is returned immediately
522  * @return NULL on error (not enough keys)
523  */
524 struct GNUNET_CRYPTO_RsaPrivateKey *
525 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
526                             uint32_t key_number,
527                             struct GNUNET_PeerIdentity *id)
528 {  
529   struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
530   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
531   
532   if ((NULL == id) || (NULL == system->hostkeys_data))
533     return NULL;
534   if (key_number >= system->total_hostkeys)
535   {
536     LOG (GNUNET_ERROR_TYPE_ERROR,
537          _("Key number %u does not exist\n"), key_number);
538     return NULL;
539   }   
540   private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
541                                               (key_number *
542                                                GNUNET_TESTING_HOSTKEYFILESIZE),
543                                               GNUNET_TESTING_HOSTKEYFILESIZE);
544   if (NULL == private_key)
545   {
546     LOG (GNUNET_ERROR_TYPE_ERROR,
547          _("Error while decoding key %u\n"), key_number);
548     return NULL;
549   }
550   GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
551   GNUNET_CRYPTO_hash (&public_key,
552                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
553                       &(id->hashPubKey));
554   return private_key;
555 }
556
557
558 /**
559  * Structure for holding data to build new configurations from a configuration
560  * template
561  */
562 struct UpdateContext
563 {
564   /**
565    * The system for which we are building configurations
566    */
567   struct GNUNET_TESTING_System *system;
568   
569   /**
570    * The configuration we are building
571    */
572   struct GNUNET_CONFIGURATION_Handle *cfg;
573
574   /**
575    * The customized service home path for this peer
576    */
577   char *service_home;
578
579   /**
580    * build status - to signal error while building a configuration
581    */
582   int status;
583 };
584
585
586 /**
587  * Function to iterate over options.  Copies
588  * the options to the target configuration,
589  * updating PORT values as needed.
590  *
591  * @param cls the UpdateContext
592  * @param section name of the section
593  * @param option name of the option
594  * @param value value of the option
595  */
596 static void
597 update_config (void *cls, const char *section, const char *option,
598                const char *value)
599 {
600   struct UpdateContext *uc = cls;
601   unsigned int ival;
602   char cval[12];
603   char uval[128];
604   char *single_variable;
605   char *per_host_variable;
606   unsigned long long num_per_host;
607   uint16_t new_port;
608
609   if (GNUNET_OK != uc->status)
610     return;
611   if (! ((0 == strcmp (option, "PORT"))
612          || (0 == strcmp (option, "UNIXPATH"))
613          || (0 == strcmp (option, "HOSTNAME"))))
614     return;
615   GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
616   GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
617   if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
618   {
619     if ((ival != 0) &&
620         (GNUNET_YES !=
621          GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
622                                                single_variable)))
623     {
624       /* FIXME: What about UDP? */
625       new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
626       if (0 == new_port)
627       {
628         uc->status = GNUNET_SYSERR;
629         GNUNET_free (single_variable);
630         GNUNET_free (per_host_variable);
631         return;
632       }
633       GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
634       value = cval;
635     }
636     else if ((ival != 0) &&
637              (GNUNET_YES ==
638               GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
639                                                     single_variable)) &&
640              GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
641                                                     per_host_variable,
642                                                     &num_per_host))
643     {
644       /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
645       /*                  ival + ctx->fdnum % num_per_host); */
646       /* value = cval; */
647       GNUNET_break (0);         /* FIXME */
648     }
649   }
650   if (0 == strcmp (option, "UNIXPATH"))
651   {
652     if (GNUNET_YES !=
653         GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
654                                               single_variable))
655     {
656       GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
657                        uc->service_home, section);
658       value = uval;
659     }
660     else if ((GNUNET_YES ==
661               GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
662                                                      per_host_variable,
663                                                      &num_per_host)) &&
664              (num_per_host > 0))
665     {
666       GNUNET_break(0);          /* FIXME */
667     }
668   }
669   if (0 == strcmp (option, "HOSTNAME"))
670   {
671     value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
672   }
673   GNUNET_free (single_variable);
674   GNUNET_free (per_host_variable);
675   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
676 }
677
678
679 /**
680  * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
681  * controller in all sections
682  *
683  * @param cls the UpdateContext
684  * @param section name of the section
685  */
686 static void
687 update_config_sections (void *cls,
688                         const char *section)
689 {
690   struct UpdateContext *uc = cls;  
691   char **ikeys;
692   char *val;
693   char *ptr;
694   char *orig_allowed_hosts;
695   char *allowed_hosts;
696   char *ACCEPT_FROM_key;
697   uint16_t ikeys_cnt;
698   uint16_t key;
699   
700   ikeys_cnt = 0;
701   val = NULL;
702   if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
703                                                      "TESTING_IGNORE_KEYS"))
704   {
705     GNUNET_assert 
706       (GNUNET_YES == 
707        GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
708                                               "TESTING_IGNORE_KEYS", &val));
709     ptr = val;
710     for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
711       ptr++;
712     if (0 == ikeys_cnt)
713       GNUNET_break (0);
714     else
715     {
716       ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
717       ptr = val;
718       for (key = 0; key < ikeys_cnt; key++)
719       {
720         ikeys[key] = ptr;
721         ptr = strstr (ptr, ";");
722         *ptr = '\0';
723         ptr++;
724       }
725     }
726   }
727   if (0 != ikeys_cnt)
728   {
729     for (key = 0; key < ikeys_cnt; key++)
730     {
731       if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
732         break;
733     }
734     if ((key == ikeys_cnt) &&
735         (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
736                                                         "ADVERTISED_PORT")))
737     {
738       if (GNUNET_OK == 
739           GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
740       {
741         GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, 
742                                                "ADVERTISED_PORT", ptr);
743         GNUNET_free (ptr);
744       }
745     }
746     for (key = 0; key < ikeys_cnt; key++)
747     {
748       if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
749       {
750         GNUNET_free (ikeys);
751         GNUNET_free (val);
752         return;
753       }
754     }
755     GNUNET_free (ikeys);
756   }
757   GNUNET_free_non_null (val);
758   ACCEPT_FROM_key = "ACCEPT_FROM";  
759   if ((NULL != uc->system->controller) && 
760       (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
761     ACCEPT_FROM_key = "ACCEPT_FROM6";
762   if (GNUNET_OK != 
763       GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
764                                              &orig_allowed_hosts))
765   {
766     orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
767   }
768   if (NULL == uc->system->controller)
769     allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
770   else
771     GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
772                      uc->system->controller);
773   GNUNET_free (orig_allowed_hosts);
774   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
775                                          allowed_hosts);
776   GNUNET_free (allowed_hosts);  
777 }
778
779
780 /**
781  * Create a new configuration using the given configuration as a template;
782  * ports and paths will be modified to select available ports on the local
783  * system. The default configuration will be available in PATHS section under
784  * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
785  * section to the temporary directory specific to this configuration. If we run
786  * out of "*port" numbers, return SYSERR.
787  *
788  * This is primarily a helper function used internally
789  * by 'GNUNET_TESTING_peer_configure'.
790  *
791  * @param system system to use to coordinate resource usage
792  * @param cfg template configuration to update
793  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
794  *           be incomplete and should not be used there upon
795  */
796 int
797 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
798                                      struct GNUNET_CONFIGURATION_Handle *cfg)
799 {
800   struct UpdateContext uc;
801   char *default_config;
802   
803   uc.system = system;
804   uc.cfg = cfg;
805   uc.status = GNUNET_OK;
806   GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
807                    system->path_counter++);
808   GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
809   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
810                                          default_config);
811   GNUNET_free (default_config);
812   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
813                                          uc.service_home);
814   /* make PORTs and UNIXPATHs unique */
815   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
816   /* allow connections to services from system controller host */
817   GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
818   /* enable loopback-based connections between peers */
819   GNUNET_CONFIGURATION_set_value_string (cfg, 
820                                          "nat",
821                                          "USE_LOCALADDR", "YES");
822   GNUNET_free (uc.service_home);
823   return uc.status;
824 }
825
826
827 /**
828  * Configure a GNUnet peer.  GNUnet must be installed on the local
829  * system and available in the PATH. 
830  *
831  * @param system system to use to coordinate resource usage
832  * @param cfg configuration to use; will be UPDATED (to reflect needed
833  *            changes in port numbers and paths)
834  * @param key_number number of the hostkey to use for the peer
835  * @param id identifier for the daemon, will be set, can be NULL
836  * @param emsg set to freshly allocated error message (set to NULL on success), 
837  *          can be NULL
838  * @return handle to the peer, NULL on error
839  */
840 struct GNUNET_TESTING_Peer *
841 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
842                                struct GNUNET_CONFIGURATION_Handle *cfg,
843                                uint32_t key_number,
844                                struct GNUNET_PeerIdentity *id,
845                                char **emsg)
846 {
847   struct GNUNET_TESTING_Peer *peer;
848   struct GNUNET_DISK_FileHandle *fd;
849   char *service_home;  
850   char hostkey_filename[128];
851   char *config_filename;
852   char *libexec_binary;
853   char *emsg_;
854   struct GNUNET_CRYPTO_RsaPrivateKey *pk;
855
856   if (NULL != emsg)
857     *emsg = NULL;
858   if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
859   {
860     GNUNET_asprintf (&emsg_,
861                        _("Failed to create configuration for peer (not enough free ports?)\n"));
862     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
863     if (NULL != emsg)
864       *emsg = emsg_;
865     else
866       GNUNET_free (emsg_);
867     return NULL;
868   }
869   if (key_number >= system->total_hostkeys)
870   {
871     GNUNET_asprintf (&emsg_,
872                      _("You attempted to create a testbed with more than %u hosts.  Please precompute more hostkeys first.\n"),
873                      (unsigned int) system->total_hostkeys);    
874     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
875     if (NULL != emsg)
876       *emsg = emsg_;
877     else
878       GNUNET_free (emsg_);
879     return NULL;
880   }
881   pk = NULL;
882   if ((NULL != id) &&
883       (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
884   {
885     GNUNET_asprintf (&emsg_,
886                      _("Failed to initialize hostkey for peer %u\n"),
887                      (unsigned int) key_number);
888     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
889     if (NULL != emsg)
890       *emsg = emsg_;
891     else
892       GNUNET_free (emsg_);
893     return NULL;
894   }
895   if (NULL != pk)
896     GNUNET_CRYPTO_rsa_key_free (pk);
897   GNUNET_assert (GNUNET_OK == 
898                  GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
899                                                         "SERVICEHOME",
900                                                         &service_home));
901   GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
902                    service_home);
903   GNUNET_free (service_home);
904   fd = GNUNET_DISK_file_open (hostkey_filename,
905                               GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
906                               GNUNET_DISK_PERM_USER_READ 
907                               | GNUNET_DISK_PERM_USER_WRITE);
908   if (NULL == fd)
909   {
910     GNUNET_break (0); 
911     return NULL;
912   }
913   if (GNUNET_TESTING_HOSTKEYFILESIZE !=
914       GNUNET_DISK_file_write (fd, system->hostkeys_data 
915                               + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
916                               GNUNET_TESTING_HOSTKEYFILESIZE))
917   {
918     GNUNET_asprintf (&emsg_,
919                      _("Failed to write hostkey file for peer %u: %s\n"),
920                      (unsigned int) key_number,
921                      STRERROR (errno));
922     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
923     if (NULL != emsg)
924       *emsg = emsg_;
925     else
926       GNUNET_free (emsg_);
927     GNUNET_DISK_file_close (fd);
928     return NULL;
929   }
930   GNUNET_DISK_file_close (fd);
931   GNUNET_assert (GNUNET_OK ==
932                  GNUNET_CONFIGURATION_get_value_string 
933                  (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));  
934   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
935   {
936     GNUNET_asprintf (&emsg_,
937                      _("Failed to write configuration file `%s' for peer %u: %s\n"),
938                      config_filename,
939                      (unsigned int) key_number,
940                      STRERROR (errno));
941     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
942     if (NULL != emsg)
943       *emsg = emsg_;
944     else
945       GNUNET_free (emsg_);
946     GNUNET_free (config_filename);
947     return NULL;
948   }
949   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
950   peer->cfgfile = config_filename; /* Free in peer_destroy */
951   libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
952   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
953   {
954     /* No prefix */
955     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
956     peer->args = strdup ("");
957   }
958   else
959     peer->args = strdup (libexec_binary);
960   peer->system = system;
961   peer->key_number = key_number;
962   GNUNET_free (libexec_binary);
963   return peer;
964 }
965
966
967 /**
968  * Obtain the peer identity from a peer handle.
969  *
970  * @param peer peer handle for which we want the peer's identity
971  * @param id identifier for the daemon, will be set
972  */
973 void
974 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
975                                   struct GNUNET_PeerIdentity *id)
976 {
977   GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
978                                                           peer->key_number,
979                                                           id));
980 }
981
982
983 /**
984  * Start the peer. 
985  *
986  * @param peer peer to start
987  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
988  */
989 int
990 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
991 {
992   if (NULL != peer->main_process)
993   {
994     GNUNET_break (0);
995     return GNUNET_SYSERR;
996   }
997   GNUNET_assert (NULL != peer->cfgfile);
998   peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL, 
999                                                 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1000                                                 NULL, NULL,
1001                                                 peer->main_binary,
1002                                                 peer->main_binary,
1003                                                 peer->args,
1004                                                 "-c",
1005                                                 peer->cfgfile,
1006                                                 NULL);
1007   if (NULL == peer->main_process)
1008   {
1009     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010                 _("Failed to start `%s': %s\n"),
1011                 peer->main_binary,
1012                 STRERROR (errno));
1013     return GNUNET_SYSERR;
1014   }
1015   return GNUNET_OK;
1016 }
1017
1018
1019 /**
1020  * Sends SIGTERM to the peer's main process
1021  *
1022  * @param peer the handle to the peer
1023  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1024  *           or upon any error while sending SIGTERM
1025  */
1026 int
1027 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1028 {
1029   if (NULL == peer->main_process)
1030   {
1031     GNUNET_break (0);
1032     return GNUNET_SYSERR;
1033   }
1034   return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1035       GNUNET_OK : GNUNET_SYSERR;
1036 }
1037
1038
1039 /**
1040  * Waits for a peer to terminate. The peer's main process will also be destroyed.
1041  *
1042  * @param peer the handle to the peer
1043  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1044  *           or upon any error while waiting
1045  */
1046 int
1047 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1048 {
1049   int ret;
1050
1051   if (NULL == peer->main_process)
1052   {
1053     GNUNET_break (0);
1054     return GNUNET_SYSERR;
1055   }
1056   ret = GNUNET_OS_process_wait (peer->main_process);
1057   GNUNET_OS_process_destroy (peer->main_process);
1058   peer->main_process = NULL;
1059   return ret;
1060 }
1061
1062
1063 /**
1064  * Stop the peer. 
1065  *
1066  * @param peer peer to stop
1067  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1068  */
1069 int
1070 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1071 {
1072   if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1073     return GNUNET_SYSERR;
1074   if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1075     return GNUNET_SYSERR;
1076   return GNUNET_OK;
1077 }
1078
1079
1080 /**
1081  * Destroy the peer.  Releases resources locked during peer configuration.
1082  * If the peer is still running, it will be stopped AND a warning will be
1083  * printed (users of the API should stop the peer explicitly first).
1084  *
1085  * @param peer peer to destroy
1086  */
1087 void
1088 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1089 {
1090   if (NULL != peer->main_process)
1091   {
1092     GNUNET_break (0);
1093     GNUNET_TESTING_peer_stop (peer);
1094   }
1095   GNUNET_free (peer->cfgfile);
1096   GNUNET_free (peer->main_binary);
1097   GNUNET_free (peer->args);
1098   GNUNET_free (peer);
1099 }
1100
1101
1102 /**
1103  * Start a single peer and run a test using the testing library.
1104  * Starts a peer using the given configuration and then invokes the
1105  * given callback.  This function ALSO initializes the scheduler loop
1106  * and should thus be called directly from "main".  The testcase
1107  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1108  *
1109  * @param testdir only the directory name without any path. This is used for
1110  *          all service homes; the directory will be created in a temporary
1111  *          location depending on the underlying OS
1112  * @param cfgfilename name of the configuration file to use;
1113  *         use NULL to only run with defaults
1114  * @param tm main function of the testcase
1115  * @param tm_cls closure for 'tm'
1116  * @return 0 on success, 1 on error
1117  */
1118 int
1119 GNUNET_TESTING_peer_run (const char *testdir,
1120                          const char *cfgfilename,
1121                          GNUNET_TESTING_TestMain tm,
1122                          void *tm_cls)
1123 {
1124   return GNUNET_TESTING_service_run (testdir, "arm",
1125                                      cfgfilename, tm, tm_cls);
1126 }
1127
1128
1129 /**
1130  * Structure for holding service data
1131  */
1132 struct ServiceContext
1133 {
1134   /**
1135    * The configuration of the peer in which the service is run
1136    */
1137   const struct GNUNET_CONFIGURATION_Handle *cfg;
1138
1139   /**
1140    * Callback to signal service startup
1141    */
1142   GNUNET_TESTING_TestMain tm;
1143   
1144   /**
1145    * The peer in which the service is run.
1146    */
1147   struct GNUNET_TESTING_Peer *peer;
1148
1149   /**
1150    * Closure for the above callback
1151    */
1152   void *tm_cls;
1153 };
1154
1155
1156 /**
1157  * Callback to be called when SCHEDULER has been started
1158  *
1159  * @param cls the ServiceContext
1160  * @param tc the TaskContext
1161  */
1162 static void
1163 service_run_main (void *cls,
1164                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1165 {
1166   struct ServiceContext *sc = cls;
1167
1168   sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1169 }
1170
1171
1172 /**
1173  * Start a single service (no ARM, except of course if the given
1174  * service name is 'arm') and run a test using the testing library.
1175  * Starts a service using the given configuration and then invokes the
1176  * given callback.  This function ALSO initializes the scheduler loop
1177  * and should thus be called directly from "main".  The testcase
1178  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1179  *
1180  * This function is useful if the testcase is for a single service
1181  * and if that service doesn't itself depend on other services.
1182  *
1183  * @param testdir only the directory name without any path. This is used for
1184  *          all service homes; the directory will be created in a temporary
1185  *          location depending on the underlying OS
1186  * @param service_name name of the service to run
1187  * @param cfgfilename name of the configuration file to use;
1188  *         use NULL to only run with defaults
1189  * @param tm main function of the testcase
1190  * @param tm_cls closure for 'tm'
1191  * @return 0 on success, 1 on error
1192  */
1193 int
1194 GNUNET_TESTING_service_run (const char *testdir,
1195                             const char *service_name,
1196                             const char *cfgfilename,
1197                             GNUNET_TESTING_TestMain tm,
1198                             void *tm_cls)
1199 {
1200   struct ServiceContext sc;
1201   struct GNUNET_TESTING_System *system;
1202   struct GNUNET_TESTING_Peer *peer;
1203   struct GNUNET_CONFIGURATION_Handle *cfg;
1204   char *binary;
1205   char *libexec_binary;
1206
1207   GNUNET_log_setup (testdir, "WARNING", NULL);
1208   system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1209   if (NULL == system)
1210     return 1;
1211   cfg = GNUNET_CONFIGURATION_create ();
1212   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1213   {
1214     LOG (GNUNET_ERROR_TYPE_ERROR,
1215          _("Failed to load configuration from %s\n"), cfgfilename);
1216     GNUNET_CONFIGURATION_destroy (cfg);
1217     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1218     return 1;
1219   }
1220   peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1221   if (NULL == peer)
1222   {
1223     GNUNET_CONFIGURATION_destroy (cfg);
1224     hostkeys_unload (system);
1225     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1226     return 1;
1227   }
1228   GNUNET_free (peer->main_binary);
1229   GNUNET_free (peer->args);
1230   GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1231   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1232   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1233   {
1234     /* No prefix */
1235     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1236     peer->args = strdup ("");
1237   }
1238   else
1239     peer->args = strdup (libexec_binary);
1240
1241   GNUNET_free (libexec_binary);
1242   GNUNET_free (binary);
1243   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1244   {    
1245     GNUNET_TESTING_peer_destroy (peer);
1246     GNUNET_CONFIGURATION_destroy (cfg);
1247     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1248     return 1;
1249   }
1250   sc.cfg = cfg;
1251   sc.tm = tm;
1252   sc.tm_cls = tm_cls;
1253   sc.peer = peer;
1254   GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1255   if ((NULL != peer->main_process) &&
1256       (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1257   {
1258     GNUNET_TESTING_peer_destroy (peer);
1259     GNUNET_CONFIGURATION_destroy (cfg);
1260     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1261     return 1;
1262   }
1263   GNUNET_TESTING_peer_destroy (peer);
1264   GNUNET_CONFIGURATION_destroy (cfg);
1265   GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1266   return 0;
1267 }
1268
1269
1270 /**
1271  * Sometimes we use the binary name to determine which specific
1272  * test to run.  In those cases, the string after the last "_"
1273  * in 'argv[0]' specifies a string that determines the configuration
1274  * file or plugin to use.  
1275  *
1276  * This function returns the respective substring, taking care
1277  * of issues such as binaries ending in '.exe' on W32.
1278  *
1279  * @param argv0 the name of the binary
1280  * @return string between the last '_' and the '.exe' (or the end of the string),
1281  *         NULL if argv0 has no '_' 
1282  */
1283 char *
1284 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1285 {
1286   size_t slen = strlen (argv0) + 1;
1287   char sbuf[slen];
1288   char *ret;
1289   char *dot;
1290
1291   memcpy (sbuf, argv0, slen);
1292   ret = strrchr (sbuf, '_');
1293   if (NULL == ret)
1294     return NULL;
1295   ret++; /* skip underscore */
1296   dot = strchr (ret, '.');
1297   if (NULL != dot)
1298     *dot = '\0';
1299   return GNUNET_strdup (ret);
1300 }
1301
1302
1303 /* end of testing.c */