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