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