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