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