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