-handle failure to load certs more nicely
[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_arm_service.h"
35 #include "gnunet_testing_lib.h"
36
37 #define LOG(kind,...)                                           \
38   GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
39
40
41 /**
42  * We need pipe control only on WINDOWS
43  */
44 #if WINDOWS
45 #define PIPE_CONTROL GNUNET_YES
46 #else
47 #define PIPE_CONTROL GNUNET_NO
48 #endif
49
50
51 /**
52  * Lowest port used for GNUnet testing.  Should be high enough to not
53  * conflict with other applications running on the hosts but be low
54  * enough to not conflict with client-ports (typically starting around
55  * 32k).
56  */
57 #define LOW_PORT 12000
58
59 /**
60  * Highest port used for GNUnet testing.  Should be low enough to not
61  * conflict with the port range for "local" ports (client apps; see
62  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
63  */
64 #define HIGH_PORT 56000
65
66
67 struct SharedServiceInstance
68 {
69   struct SharedService *ss;
70
71   char *cfg_fn;
72
73   struct GNUNET_OS_Process *proc;
74
75   char *unix_sock;
76
77   char *port_str;
78
79   unsigned int n_refs;
80 };
81
82 struct SharedService
83 {
84   char *sname;
85
86   struct SharedServiceInstance **instances;
87
88   struct GNUNET_CONFIGURATION_Handle *cfg;
89
90   unsigned int n_peers;
91
92   unsigned int share;
93
94   unsigned int n_instances;
95 };
96
97
98 /**
99  * Handle for a system on which GNUnet peers are executed;
100  * a system is used for reserving unique paths and ports.
101  */
102 struct GNUNET_TESTING_System
103 {
104   /**
105    * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
106    * SERVICEHOME.    */
107   char *tmppath;
108
109   /**
110    * The trusted ip. Can either be a single ip address or a network address in
111    * CIDR notation.
112    */
113   char *trusted_ip;
114
115   /**
116    * our hostname
117    */
118   char *hostname;
119
120   /**
121    * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
122    */
123   char *hostkeys_data;
124
125   /**
126    * memory map for 'hostkeys_data'.
127    */
128   struct GNUNET_DISK_MapHandle *map;
129
130   struct SharedService **shared_services;
131
132   unsigned int n_shared_services;
133
134   /**
135    * Bitmap where each port that has already been reserved for some GNUnet peer
136    * is recorded.  Note that we make no distinction between TCP and UDP ports
137    * and test if a port is already in use before assigning it to a peer/service.
138    * If we detect that a port is already in use, we also mark it in this bitmap.
139    * So all the bits that are zero merely indicate ports that MIGHT be available
140    * for peers.
141    */
142   uint32_t reserved_ports[65536 / 32];
143
144   /**
145    * Counter we use to make service home paths unique on this system;
146    * the full path consists of the tmppath and this number.  Each
147    * UNIXPATH for a peer is also modified to include the respective
148    * path counter to ensure uniqueness.  This field is incremented
149    * by one for each configured peer.  Even if peers are destroyed,
150    * we never re-use path counters.
151    */
152   uint32_t path_counter;  
153
154   /**
155    * The number of hostkeys
156    */
157   uint32_t total_hostkeys;
158
159   /**
160    * Lowest port we are allowed to use.
161    */
162   uint16_t lowport;
163
164   /**
165    * Highest port we are allowed to use.
166    */
167   uint16_t highport;
168 };
169
170
171 /**
172  * Handle for a GNUnet peer controlled by testing.
173  */
174 struct GNUNET_TESTING_Peer
175 {
176   /**
177    * The TESTING system associated with this peer
178    */
179   struct GNUNET_TESTING_System *system;
180
181   /**
182    * Path to the configuration file for this peer.
183    */
184   char *cfgfile;
185
186   /**
187    * Binary to be executed during 'GNUNET_TESTING_peer_start'.
188    * Typically 'gnunet-service-arm' (but can be set to a 
189    * specific service by 'GNUNET_TESTING_service_run' if
190    * necessary).
191    */ 
192   char *main_binary;
193   char *args;
194   
195   /**
196    * Handle to the running binary of the service, NULL if the
197    * peer/service is currently not running.
198    */
199   struct GNUNET_OS_Process *main_process;
200
201   /**
202    * The handle to the peer's ARM service
203    */
204   struct GNUNET_ARM_Handle *ah;
205
206   /**
207    * Handle to ARM monitoring
208    */
209   struct GNUNET_ARM_MonitorHandle *mh;
210
211   /**
212    * The config of the peer
213    */
214   struct GNUNET_CONFIGURATION_Handle *cfg;
215
216   /**
217    * The callback to call asynchronously when a peer is stopped
218    */  
219   GNUNET_TESTING_PeerStopCallback cb;
220   
221   /**
222    * The closure for the above callback
223    */
224   void *cb_cls;
225   
226   /**
227    * The cached identity of this peer.  Will be populated on call to
228    * GNUNET_TESTING_peer_get_identity()
229    */
230   struct GNUNET_PeerIdentity *id;
231
232   struct SharedServiceInstance **ss_instances;
233
234   /**
235    * Array of ports currently allocated to this peer.  These ports will be
236    * released upon peer destroy and can be used by other peers which are
237    * configured after.
238    */
239   uint16_t *ports;
240
241   /**
242    * The number of ports in the above array
243    */
244   unsigned int nports;
245
246   /**
247    * The keynumber of this peer's hostkey
248    */
249   uint32_t key_number;
250 };
251
252
253 /**
254  * Testing includes a number of pre-created hostkeys for faster peer
255  * startup. This function loads such keys into memory from a file.
256  *
257  * @param system the testing system handle
258  * @return GNUNET_OK on success; GNUNET_SYSERR on error
259  */
260 static int
261 hostkeys_load (struct GNUNET_TESTING_System *system)
262 {
263   uint64_t fs; 
264   char *data_dir;
265   char *filename;
266   struct GNUNET_DISK_FileHandle *fd;
267
268   GNUNET_assert (NULL == system->hostkeys_data);
269   data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
270   GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
271   GNUNET_free (data_dir);  
272
273   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
274   {
275     LOG (GNUNET_ERROR_TYPE_ERROR,
276          _("Hostkeys file not found: %s\n"), filename);
277     GNUNET_free (filename);
278     return GNUNET_SYSERR;
279   }
280   /* Check hostkey file size, read entire thing into memory */
281   if (GNUNET_OK != 
282       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
283     fs = 0;
284   if (0 == fs)
285   {
286     GNUNET_free (filename);
287     return GNUNET_SYSERR;       /* File is empty */
288   }
289   if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
290   {
291     LOG (GNUNET_ERROR_TYPE_ERROR,
292          _("Incorrect hostkey file format: %s\n"), filename);
293     GNUNET_free (filename);
294     return GNUNET_SYSERR;
295   }
296   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
297                                          GNUNET_DISK_PERM_NONE);
298   if (NULL == fd)
299   {
300     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
301     GNUNET_free (filename);
302     return GNUNET_SYSERR;
303   }
304   GNUNET_free (filename);
305   system->hostkeys_data = GNUNET_DISK_file_map (fd,
306                                                 &system->map,
307                                                 GNUNET_DISK_MAP_TYPE_READ,
308                                                 fs);
309   GNUNET_DISK_file_close (fd);
310   if (NULL == system->hostkeys_data)
311     return GNUNET_SYSERR;
312   system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
313   return GNUNET_OK;
314 }
315
316
317 /**
318  * Function to remove the loaded hostkeys
319  *
320  * @param system the testing system handle
321  */
322 static void
323 hostkeys_unload (struct GNUNET_TESTING_System *system)
324 {
325   GNUNET_break (NULL != system->hostkeys_data);
326   system->hostkeys_data = NULL;
327   GNUNET_DISK_file_unmap (system->map);
328   system->map = NULL;
329   system->hostkeys_data = NULL;
330   system->total_hostkeys = 0;
331 }
332
333
334 /**
335  * Function to iterate over options.
336  *
337  * @param cls closure
338  * @param section name of the section
339  * @param option name of the option
340  * @param value value of the option
341  */
342 static void
343 cfg_copy_iterator (void *cls, const char *section,
344                    const char *option, const char *value)
345 {
346   struct GNUNET_CONFIGURATION_Handle *cfg2 = cls;
347
348   GNUNET_CONFIGURATION_set_value_string (cfg2, section, option, value);
349 }
350
351
352 /**
353  * Create a system handle.  There must only be one system
354  * handle per operating system.
355  *
356  * @param testdir only the directory name without any path. This is used for
357  *          all service homes; the directory will be created in a temporary
358  *          location depending on the underlying OS
359  * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
360  *          service configurations generated to allow control connections from
361  *          this ip. This can either be a single ip address or a network address
362  *          in CIDR notation.
363  * @param hostname the hostname of the system we are using for testing; NULL for
364  *          localhost
365  * @param shared_services NULL terminated array describing services that are to
366  *          be shared among peers
367  * @param lowport lowest port number this system is allowed to allocate (inclusive)
368  * @param highport highest port number this system is allowed to allocate (exclusive)
369  * @return handle to this system, NULL on error
370  */
371 struct GNUNET_TESTING_System *
372 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
373                                              const char *trusted_ip,
374                                              const char *hostname,
375                                              const struct
376                                              GNUNET_TESTING_SharedService *
377                                              shared_services,
378                                              uint16_t lowport,
379                                              uint16_t highport)
380 {
381   struct GNUNET_TESTING_System *system;
382   struct GNUNET_TESTING_SharedService tss;
383   struct SharedService *ss;
384   unsigned int cnt;
385
386   GNUNET_assert (NULL != testdir);
387   system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
388   system->tmppath = GNUNET_DISK_mkdtemp (testdir);
389   system->lowport = lowport;
390   system->highport = highport;
391   if (NULL == system->tmppath)
392   {
393     GNUNET_free (system);
394     return NULL;
395   }
396   if (NULL != trusted_ip)
397     system->trusted_ip = GNUNET_strdup (trusted_ip);
398   if (NULL != hostname)
399     system->hostname = GNUNET_strdup (hostname);
400   if (GNUNET_OK != hostkeys_load (system))
401   {
402     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
403     return NULL;
404   }
405   if (NULL == shared_services)
406     return system;
407   for (cnt = 0; NULL != shared_services[cnt].service; cnt++)
408   {
409     tss = shared_services[cnt];
410     ss = GNUNET_malloc (sizeof (struct SharedService));
411     ss->sname = GNUNET_strdup (tss.service);
412     ss->cfg = GNUNET_CONFIGURATION_create ();
413     GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, ss->sname,
414                                                  &cfg_copy_iterator, ss->cfg);
415     GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, "TESTING",
416                                                  &cfg_copy_iterator, ss->cfg);
417     ss->share = tss.share;
418     GNUNET_array_append (system->shared_services, system->n_shared_services,
419                          ss);
420   }
421   return system;
422 }
423
424
425 /**
426  * Create a system handle.  There must only be one system handle per operating
427  * system.  Uses a default range for allowed ports.  Ports are still tested for
428  * availability.
429  *
430  * @param testdir only the directory name without any path. This is used for all
431  *          service homes; the directory will be created in a temporary location
432  *          depending on the underlying OS
433  * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
434  *          service configurations generated to allow control connections from
435  *          this ip. This can either be a single ip address or a network address
436  *          in CIDR notation.
437  * @param hostname the hostname of the system we are using for testing; NULL for
438  *          localhost
439  * @param shared_services NULL terminated array describing services that are to
440  *          be shared among peers
441  * @return handle to this system, NULL on error
442  */
443 struct GNUNET_TESTING_System *
444 GNUNET_TESTING_system_create (const char *testdir,
445                               const char *trusted_ip,
446                               const char *hostname,
447                               const struct GNUNET_TESTING_SharedService *
448                               shared_services)
449 {
450   return GNUNET_TESTING_system_create_with_portrange (testdir,
451                                                       trusted_ip,
452                                                       hostname,
453                                                       shared_services,
454                                                       LOW_PORT,
455                                                       HIGH_PORT);
456 }
457
458 static void
459 cleanup_shared_service_instance (struct SharedServiceInstance *i)
460 {
461   if (NULL != i->cfg_fn)
462   {
463     (void) unlink (i->cfg_fn);
464     GNUNET_free (i->cfg_fn);
465   }
466   GNUNET_free_non_null (i->unix_sock);
467   GNUNET_free_non_null (i->port_str);
468   GNUNET_break (NULL == i->proc);
469   GNUNET_break (0 == i->n_refs);
470   GNUNET_free (i);
471 }
472
473 static int
474 start_shared_service_instance (struct SharedServiceInstance *i)
475 {
476   char *binary;
477   char *libexec_binary;
478
479   GNUNET_assert (NULL == i->proc);
480   GNUNET_assert (NULL != i->cfg_fn);
481   (void) GNUNET_asprintf (&binary, "gnunet-service-%s", i->ss->sname);
482   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
483   GNUNET_free (binary);
484   i->proc = GNUNET_OS_start_process (PIPE_CONTROL,
485                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
486                                      NULL, NULL,
487                                      libexec_binary,
488                                      libexec_binary,
489                                      "-c",
490                                      i->cfg_fn,
491                                      NULL);
492   GNUNET_free (libexec_binary);
493   if (NULL == i->proc)
494     return GNUNET_SYSERR;
495   return GNUNET_OK;
496 }
497
498
499 static void
500 stop_shared_service_instance (struct SharedServiceInstance *i)
501 {
502   GNUNET_break (0 == i->n_refs);
503   if (0 != GNUNET_OS_process_kill (i->proc, SIGTERM))
504     LOG (GNUNET_ERROR_TYPE_WARNING,
505          "Killing shared service instance (%s) failed\n", i->ss->sname);
506   (void) GNUNET_OS_process_wait (i->proc);
507   GNUNET_OS_process_destroy (i->proc);
508   i->proc = NULL;
509 }
510
511
512 /**
513  * Free system resources.
514  *
515  * @param system system to be freed
516  * @param remove_paths should the 'testdir' and all subdirectories
517  *        be removed (clean up on shutdown)?
518  */
519 void
520 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
521                                int remove_paths)
522 {
523   struct SharedService *ss;
524   struct SharedServiceInstance *i;
525   unsigned int ss_cnt;
526   unsigned int i_cnt;
527
528   if (NULL != system->hostkeys_data)
529     hostkeys_unload (system);
530   for (ss_cnt = 0; ss_cnt < system->n_shared_services; ss_cnt++)
531   {
532     ss = system->shared_services[ss_cnt];
533     for (i_cnt = 0; i_cnt < ss->n_instances; i_cnt++)
534     {
535       i = ss->instances[i_cnt];
536       if (NULL != i->proc)
537         stop_shared_service_instance (i);
538       cleanup_shared_service_instance (i);
539     }
540     GNUNET_free_non_null (ss->instances);
541     GNUNET_CONFIGURATION_destroy (ss->cfg);
542     GNUNET_free (ss->sname);
543     GNUNET_free (ss);
544   }
545   GNUNET_free_non_null (system->shared_services);
546   if (GNUNET_YES == remove_paths)
547     GNUNET_DISK_directory_remove (system->tmppath);
548   GNUNET_free (system->tmppath);
549   GNUNET_free_non_null (system->trusted_ip);
550   GNUNET_free_non_null (system->hostname);
551   GNUNET_free (system);
552 }
553
554
555 /**
556  * Reserve a TCP or UDP port for a peer.
557  *
558  * @param system system to use for reservation tracking
559  * @return 0 if no free port was available
560  */
561 uint16_t 
562 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system)
563 {
564   struct GNUNET_NETWORK_Handle *socket;
565   struct addrinfo hint;
566   struct addrinfo *ret;
567   struct addrinfo *ai;
568   uint32_t *port_buckets;
569   char *open_port_str;
570   int bind_status;
571   uint32_t xor_image;
572   uint16_t index;
573   uint16_t open_port;
574   uint16_t pos;
575
576   /*
577   FIXME: Instead of using getaddrinfo we should try to determine the port
578          status by the following heurestics.
579   
580          On systems which support both IPv4 and IPv6, only ports open on both
581          address families are considered open.
582          On system with either IPv4 or IPv6. A port is considered open if it's
583          open in the respective address family
584   */
585   hint.ai_family = AF_UNSPEC;   /* IPv4 and IPv6 */
586   hint.ai_socktype = 0;
587   hint.ai_protocol = 0;
588   hint.ai_addrlen = 0;
589   hint.ai_addr = NULL;
590   hint.ai_canonname = NULL;
591   hint.ai_next = NULL;
592   hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;  /* Wild card address */
593   port_buckets = system->reserved_ports;
594   for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
595   {
596     xor_image = (UINT32_MAX ^ port_buckets[index]);
597     if (0 == xor_image)        /* Ports in the bucket are full */
598       continue;
599     pos = system->lowport % 32;
600     while (pos < 32)
601     {
602       if (0 == ((xor_image >> pos) & 1U))
603       {
604         pos++;
605         continue;
606       }
607       open_port = (index * 32) + pos;
608       if (open_port >= system->highport)
609         return 0;
610       GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
611       ret = NULL;
612       GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
613       GNUNET_free (open_port_str);
614       bind_status = GNUNET_NO;
615       for (ai = ret; NULL != ai; ai = ai->ai_next)
616       {
617         socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_STREAM, 0);
618         if (NULL == socket)
619           continue;
620         bind_status = GNUNET_NETWORK_socket_bind (socket,
621                                                   ai->ai_addr,
622                                                   ai->ai_addrlen,
623                                                   0);
624         GNUNET_NETWORK_socket_close (socket);
625         if (GNUNET_OK != bind_status)
626           break;
627         socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_DGRAM, 0);
628         if (NULL == socket)
629           continue;
630         bind_status = GNUNET_NETWORK_socket_bind (socket,
631                                                   ai->ai_addr,
632                                                   ai->ai_addrlen,
633                                                   0);
634         GNUNET_NETWORK_socket_close (socket);
635         if (GNUNET_OK != bind_status)
636           break;
637       }
638       port_buckets[index] |= (1U << pos); /* Set the port bit */
639       freeaddrinfo (ret);
640       if (GNUNET_OK == bind_status)
641       {
642         LOG (GNUNET_ERROR_TYPE_DEBUG,
643              "Found a free port %u\n", (unsigned int) open_port);
644         return open_port;
645       }
646       pos++;
647     }
648   }
649   return 0;
650 }
651
652
653 /**
654  * Release reservation of a TCP or UDP port for a peer
655  * (used during GNUNET_TESTING_peer_destroy).
656  *
657  * @param system system to use for reservation tracking
658  * @param port reserved port to release
659  */
660 void
661 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
662                              uint16_t port)
663 {
664   uint32_t *port_buckets;
665   uint16_t bucket;
666   uint16_t pos;
667
668   port_buckets = system->reserved_ports;
669   bucket = port / 32;
670   pos = port % 32;
671   LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
672   if (0 == (port_buckets[bucket] & (1U << pos)))
673   {
674     GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
675     return;
676   }
677   port_buckets[bucket] &= ~(1U << pos);
678 }
679
680
681 /**
682  * Testing includes a number of pre-created hostkeys for
683  * faster peer startup.  This function can be used to
684  * access the n-th key of those pre-created hostkeys; note
685  * that these keys are ONLY useful for testing and not
686  * secure as the private keys are part of the public 
687  * GNUnet source code.
688  *
689  * This is primarily a helper function used internally
690  * by 'GNUNET_TESTING_peer_configure'.
691  *
692  * @param system the testing system handle
693  * @param key_number desired pre-created hostkey to obtain
694  * @param id set to the peer's identity (hash of the public
695  *        key; if NULL, GNUNET_SYSERR is returned immediately
696  * @return NULL on error (not enough keys)
697  */
698 struct GNUNET_CRYPTO_EccPrivateKey *
699 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
700                             uint32_t key_number,
701                             struct GNUNET_PeerIdentity *id)
702 {  
703   struct GNUNET_CRYPTO_EccPrivateKey *private_key;
704   struct GNUNET_CRYPTO_EccPublicSignKey public_key;
705   
706   if ((NULL == id) || (NULL == system->hostkeys_data))
707     return NULL;
708   if (key_number >= system->total_hostkeys)
709   {
710     LOG (GNUNET_ERROR_TYPE_ERROR,
711          _("Key number %u does not exist\n"), key_number);
712     return NULL;
713   }   
714   private_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
715   memcpy (private_key,
716           system->hostkeys_data +
717           (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
718           GNUNET_TESTING_HOSTKEYFILESIZE);
719   if (NULL == private_key)
720   {
721     LOG (GNUNET_ERROR_TYPE_ERROR,
722          _("Error while decoding key %u\n"), key_number);
723     return NULL;
724   }
725   GNUNET_CRYPTO_ecc_key_get_public_for_signature (private_key, &public_key);
726   GNUNET_CRYPTO_hash (&public_key,
727                       sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
728                       &(id->hashPubKey));
729   return private_key;
730 }
731
732
733 /**
734  * Structure for holding data to build new configurations from a configuration
735  * template
736  */
737 struct UpdateContext
738 {
739   /**
740    * The system for which we are building configurations
741    */
742   struct GNUNET_TESTING_System *system;
743   
744   /**
745    * The configuration we are building
746    */
747   struct GNUNET_CONFIGURATION_Handle *cfg;
748
749   /**
750    * The customized service home path for this peer
751    */
752   char *service_home;
753
754   /**
755    * Array of ports currently allocated to this peer.  These ports will be
756    * released upon peer destroy and can be used by other peers which are
757    * configured after.
758    */
759   uint16_t *ports;
760
761   /**
762    * The number of ports in the above array
763    */
764   unsigned int nports;
765
766   /**
767    * build status - to signal error while building a configuration
768    */
769   int status;
770 };
771
772
773 /**
774  * Function to iterate over options.  Copies
775  * the options to the target configuration,
776  * updating PORT values as needed.
777  *
778  * @param cls the UpdateContext
779  * @param section name of the section
780  * @param option name of the option
781  * @param value value of the option
782  */
783 static void
784 update_config (void *cls, const char *section, const char *option,
785                const char *value)
786 {
787   struct UpdateContext *uc = cls;
788   unsigned int ival;
789   char cval[12];
790   char uval[128];
791   char *single_variable;
792   char *per_host_variable;
793   unsigned long long num_per_host;
794   uint16_t new_port;
795
796   if (GNUNET_OK != uc->status)
797     return;
798   if (! ((0 == strcmp (option, "PORT"))
799          || (0 == strcmp (option, "UNIXPATH"))
800          || (0 == strcmp (option, "HOSTNAME"))))
801     return;
802   GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
803   GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
804   if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
805   {
806     if ((ival != 0) &&
807         (GNUNET_YES !=
808          GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
809                                                single_variable)))
810     {
811       new_port = GNUNET_TESTING_reserve_port (uc->system);
812       if (0 == new_port)
813       {
814         uc->status = GNUNET_SYSERR;
815         GNUNET_free (single_variable);
816         GNUNET_free (per_host_variable);
817         return;
818       }
819       GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
820       value = cval;
821       GNUNET_array_append (uc->ports, uc->nports, new_port);
822     }
823     else if ((ival != 0) &&
824              (GNUNET_YES ==
825               GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
826                                                     single_variable)) &&
827              GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
828                                                     per_host_variable,
829                                                     &num_per_host))
830     {
831       /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
832       /*                  ival + ctx->fdnum % num_per_host); */
833       /* value = cval; */
834       GNUNET_break (0);         /* FIXME */
835     }
836   }
837   if (0 == strcmp (option, "UNIXPATH"))
838   {
839     if (GNUNET_YES !=
840         GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
841                                               single_variable))
842     {
843       GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
844                        uc->service_home, section);
845       value = uval;
846     }
847     else if ((GNUNET_YES ==
848               GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
849                                                      per_host_variable,
850                                                      &num_per_host)) &&
851              (num_per_host > 0))
852     {
853       GNUNET_break(0);          /* FIXME */
854     }
855   }
856   if (0 == strcmp (option, "HOSTNAME"))
857   {
858     value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
859   }
860   GNUNET_free (single_variable);
861   GNUNET_free (per_host_variable);
862   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
863 }
864
865
866 /**
867  * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
868  * 'trusted_hosts' in all sections
869  *
870  * @param cls the UpdateContext
871  * @param section name of the section
872  */
873 static void
874 update_config_sections (void *cls,
875                         const char *section)
876 {
877   struct UpdateContext *uc = cls;  
878   char **ikeys;
879   char *val;
880   char *ptr;
881   char *orig_allowed_hosts;
882   char *allowed_hosts;
883   char *ACCEPT_FROM_key;
884   uint16_t ikeys_cnt;
885   uint16_t key;
886   
887   ikeys_cnt = 0;
888   val = NULL;
889   /* Ignore certain options from sections.  See
890      https://gnunet.org/bugs/view.php?id=2476 */
891   if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
892                                                      "TESTING_IGNORE_KEYS"))
893   {
894     GNUNET_assert 
895       (GNUNET_YES == 
896        GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
897                                               "TESTING_IGNORE_KEYS", &val));
898     ptr = val;
899     for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
900       ptr++;
901     if (0 == ikeys_cnt)
902       GNUNET_break (0);
903     else
904     {
905       ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
906       ptr = val;
907       for (key = 0; key < ikeys_cnt; key++)
908       {
909         ikeys[key] = ptr;
910         ptr = strstr (ptr, ";");
911         *ptr = '\0';
912         ptr++;
913       }
914     }
915   }
916   if (0 != ikeys_cnt)
917   {
918     for (key = 0; key < ikeys_cnt; key++)
919     {
920       if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
921         break;
922     }
923     if ((key == ikeys_cnt) &&
924         (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
925                                                         "ADVERTISED_PORT")))
926     {
927       if (GNUNET_OK == 
928           GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
929       {
930         GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, 
931                                                "ADVERTISED_PORT", ptr);
932         GNUNET_free (ptr);
933       }
934     }
935     for (key = 0; key < ikeys_cnt; key++)
936     {
937       if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
938       {
939         GNUNET_free (ikeys);
940         GNUNET_free (val);
941         return;
942       }
943     }
944     GNUNET_free (ikeys);
945   }
946   GNUNET_free_non_null (val);
947   ACCEPT_FROM_key = "ACCEPT_FROM";  
948   if ((NULL != uc->system->trusted_ip) && 
949       (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
950     ACCEPT_FROM_key = "ACCEPT_FROM6";
951   if (GNUNET_OK != 
952       GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
953                                              &orig_allowed_hosts))
954   {
955     orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
956   }
957   if (NULL == uc->system->trusted_ip)
958     allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
959   else
960     GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
961                      uc->system->trusted_ip);
962   GNUNET_free (orig_allowed_hosts);
963   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
964                                          allowed_hosts);
965   GNUNET_free (allowed_hosts);  
966 }
967
968 static struct SharedServiceInstance *
969 associate_shared_service (struct GNUNET_TESTING_System *system,
970                           struct SharedService *ss,
971                           struct GNUNET_CONFIGURATION_Handle *cfg)
972 {
973   struct SharedServiceInstance *i;
974   struct GNUNET_CONFIGURATION_Handle *temp;
975   char *service_home;
976   uint32_t port;
977
978   ss->n_peers++;
979   if ( ((0 == ss->share) && (NULL == ss->instances))
980        ||
981        ( (0 != ss->share) 
982          && (ss->n_instances < ((ss->n_peers + ss->share - 1) / ss->share)) ) )
983   {    
984     i = GNUNET_malloc (sizeof (struct SharedServiceInstance));
985     i->ss = ss;
986     (void) GNUNET_asprintf (&service_home, "%s/shared/%s/%u",
987                             system->tmppath, ss->sname, ss->n_instances);
988     (void) GNUNET_asprintf (&i->unix_sock, "%s/sock", service_home);
989     port = GNUNET_TESTING_reserve_port (system);
990     if (0 == port)
991     {
992       GNUNET_free (service_home);
993       cleanup_shared_service_instance (i);
994       return NULL;
995     }
996     GNUNET_array_append (ss->instances, ss->n_instances, i);
997     temp = GNUNET_CONFIGURATION_dup (ss->cfg);
998     (void) GNUNET_asprintf (&i->port_str, "%u", port);
999     (void) GNUNET_asprintf (&i->cfg_fn, "%s/config", service_home);
1000     GNUNET_CONFIGURATION_set_value_string (temp, "PATHS", "SERVICEHOME",
1001                                            service_home);
1002     GNUNET_free (service_home);
1003     GNUNET_CONFIGURATION_set_value_string (temp, ss->sname, "UNIXPATH",
1004                                            i->unix_sock);
1005     GNUNET_CONFIGURATION_set_value_string (temp, ss->sname, "PORT",
1006                                            i->port_str);
1007     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_write (temp, i->cfg_fn))
1008     {
1009       GNUNET_CONFIGURATION_destroy (temp);
1010       cleanup_shared_service_instance (i);
1011       return NULL;
1012     }
1013     GNUNET_CONFIGURATION_destroy (temp);
1014   }
1015   else
1016   {
1017     GNUNET_assert (NULL != ss->instances);
1018     GNUNET_assert (0 < ss->n_instances);
1019     i = ss->instances[ss->n_instances - 1];
1020   }
1021   GNUNET_CONFIGURATION_iterate_section_values(ss->cfg, ss->sname, 
1022                                               &cfg_copy_iterator, cfg);
1023   GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "UNIXPATH",
1024                                          i->unix_sock);
1025   GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "PORT", i->port_str);
1026   return i;
1027 }
1028
1029
1030 /**
1031  * Create a new configuration using the given configuration as a template;
1032  * ports and paths will be modified to select available ports on the local
1033  * system. The default configuration will be available in PATHS section under
1034  * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
1035  * section to the temporary directory specific to this configuration. If we run
1036  * out of "*port" numbers, return SYSERR.
1037  *
1038  * This is primarily a helper function used internally
1039  * by 'GNUNET_TESTING_peer_configure'.
1040  *
1041  * @param system system to use to coordinate resource usage
1042  * @param cfg template configuration to update
1043  * @param ports array with port numbers used in the created configuration.
1044  *          Will be updated upon successful return.  Can be NULL
1045  * @param nports the size of the `ports' array.  Will be updated.
1046  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
1047  *           be incomplete and should not be used there upon
1048  */
1049 static int
1050 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
1051                                       struct GNUNET_CONFIGURATION_Handle *cfg,
1052                                       uint16_t **ports,
1053                                       unsigned int *nports)
1054 {
1055   struct UpdateContext uc;
1056   char *default_config;  
1057
1058   uc.system = system;
1059   uc.cfg = cfg;
1060   uc.status = GNUNET_OK;
1061   uc.ports = NULL;
1062   uc.nports = 0;
1063   GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
1064                    system->path_counter++);
1065   GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
1066   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1067                                          default_config);
1068   GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
1069                                          default_config);
1070   GNUNET_free (default_config);
1071   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
1072                                          uc.service_home);
1073   /* make PORTs and UNIXPATHs unique */
1074   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
1075   /* allow connections to services from system trusted_ip host */
1076   GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
1077   /* enable loopback-based connections between peers */
1078   GNUNET_CONFIGURATION_set_value_string (cfg, 
1079                                          "nat",
1080                                          "USE_LOCALADDR", "YES");
1081   GNUNET_free (uc.service_home);
1082   if ((NULL != ports) && (NULL != nports))
1083   {
1084     *ports = uc.ports;
1085     *nports = uc.nports;
1086   }
1087   else
1088     GNUNET_free_non_null (uc.ports);
1089   return uc.status;
1090 }
1091
1092
1093 /**
1094  * Create a new configuration using the given configuration as a template;
1095  * ports and paths will be modified to select available ports on the local
1096  * system. The default configuration will be available in PATHS section under
1097  * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
1098  * section to the temporary directory specific to this configuration. If we run
1099  * out of "*port" numbers, return SYSERR.
1100  *
1101  * This is primarily a helper function used internally
1102  * by 'GNUNET_TESTING_peer_configure'.
1103  *
1104  * @param system system to use to coordinate resource usage
1105  * @param cfg template configuration to update
1106  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
1107  *           be incomplete and should not be used there upon
1108  */
1109 int
1110 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
1111                                      struct GNUNET_CONFIGURATION_Handle *cfg)
1112 {
1113   return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
1114 }
1115
1116
1117 /**
1118  * Configure a GNUnet peer.  GNUnet must be installed on the local
1119  * system and available in the PATH. 
1120  *
1121  * @param system system to use to coordinate resource usage
1122  * @param cfg configuration to use; will be UPDATED (to reflect needed
1123  *            changes in port numbers and paths)
1124  * @param key_number number of the hostkey to use for the peer
1125  * @param id identifier for the daemon, will be set, can be NULL
1126  * @param emsg set to freshly allocated error message (set to NULL on success), 
1127  *          can be NULL
1128  * @return handle to the peer, NULL on error
1129  */
1130 struct GNUNET_TESTING_Peer *
1131 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
1132                                struct GNUNET_CONFIGURATION_Handle *cfg,
1133                                uint32_t key_number,
1134                                struct GNUNET_PeerIdentity *id,
1135                                char **emsg)
1136 {
1137   struct GNUNET_TESTING_Peer *peer;
1138   struct GNUNET_DISK_FileHandle *fd;
1139   char *hostkey_filename;
1140   char *config_filename;
1141   char *libexec_binary;
1142   char *emsg_;
1143   struct GNUNET_CRYPTO_EccPrivateKey *pk;
1144   uint16_t *ports;
1145   struct SharedService *ss;
1146   struct SharedServiceInstance **ss_instances;
1147   unsigned int cnt;
1148   unsigned int nports;      
1149
1150   ports = NULL;
1151   nports = 0;
1152   ss_instances = NULL;
1153   if (NULL != emsg)
1154     *emsg = NULL;
1155   if (key_number >= system->total_hostkeys)
1156   {
1157     GNUNET_asprintf (&emsg_,
1158                      _("You attempted to create a testbed with more than %u hosts.  Please precompute more hostkeys first.\n"),
1159                      (unsigned int) system->total_hostkeys);    
1160     goto err_ret;
1161   }
1162   pk = NULL;
1163   if ((NULL != id) &&
1164       (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
1165   {
1166     GNUNET_asprintf (&emsg_,
1167                      _("Failed to initialize hostkey for peer %u\n"),
1168                      (unsigned int) key_number);
1169     goto err_ret;
1170   }  
1171   if (NULL != pk)
1172     GNUNET_free (pk);
1173   if (GNUNET_NO == 
1174       GNUNET_CONFIGURATION_have_value (cfg, "PEER", "PRIVATE_KEY"))
1175   {
1176     GNUNET_asprintf (&emsg_, 
1177                      _("PRIVATE_KEY option in PEER section missing in configuration\n"));
1178     goto err_ret;
1179   }
1180   /* Remove sections for shared services */
1181   for (cnt = 0; cnt < system->n_shared_services; cnt++)
1182   {
1183     ss = system->shared_services[cnt];
1184     GNUNET_CONFIGURATION_remove_section (cfg, ss->sname);
1185   }
1186   if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
1187                                                          &ports, &nports))
1188   {
1189     GNUNET_asprintf (&emsg_,
1190                      _("Failed to create configuration for peer "
1191                        "(not enough free ports?)\n"));
1192     goto err_ret;
1193   }
1194   GNUNET_assert (GNUNET_OK == 
1195                  GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER",
1196                                                           "PRIVATE_KEY",
1197                                                           &hostkey_filename));
1198   fd = GNUNET_DISK_file_open (hostkey_filename,
1199                               GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
1200                               GNUNET_DISK_PERM_USER_READ 
1201                               | GNUNET_DISK_PERM_USER_WRITE);
1202   if (NULL == fd)
1203   {
1204     GNUNET_asprintf (&emsg_, _("Cannot open hostkey file `%s': %s\n"),
1205                      hostkey_filename, STRERROR (errno));
1206     GNUNET_free (hostkey_filename);
1207     goto err_ret;
1208   }
1209   GNUNET_free (hostkey_filename);
1210   if (GNUNET_TESTING_HOSTKEYFILESIZE !=
1211       GNUNET_DISK_file_write (fd, system->hostkeys_data 
1212                               + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
1213                               GNUNET_TESTING_HOSTKEYFILESIZE))
1214   {
1215     GNUNET_asprintf (&emsg_,
1216                      _("Failed to write hostkey file for peer %u: %s\n"),
1217                      (unsigned int) key_number,
1218                      STRERROR (errno));
1219     GNUNET_DISK_file_close (fd);
1220     goto err_ret;
1221   }
1222   GNUNET_DISK_file_close (fd);
1223   ss_instances = GNUNET_malloc (sizeof (struct SharedServiceInstance *)
1224                                 * system->n_shared_services);
1225   for (cnt=0; cnt < system->n_shared_services; cnt++)
1226   {
1227     ss = system->shared_services[cnt];
1228     ss_instances[cnt] = associate_shared_service (system, ss, cfg);
1229     if (NULL == ss_instances[cnt])
1230       goto err_ret;
1231   }  
1232   GNUNET_assert (GNUNET_OK ==
1233                  GNUNET_CONFIGURATION_get_value_string 
1234                  (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));  
1235   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1236   {
1237     GNUNET_asprintf (&emsg_,
1238                      _("Failed to write configuration file `%s' for peer %u: %s\n"),
1239                      config_filename,
1240                      (unsigned int) key_number,
1241                      STRERROR (errno));    
1242     GNUNET_free (config_filename);
1243     goto err_ret;
1244   }
1245   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
1246   peer->ss_instances = ss_instances;
1247   peer->cfgfile = config_filename; /* Free in peer_destroy */
1248   peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1249   libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1250   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1251   {
1252     /* No prefix */
1253     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1254     peer->args = strdup ("");
1255   }
1256   else
1257     peer->args = strdup (libexec_binary);
1258   peer->system = system;
1259   peer->key_number = key_number;
1260   GNUNET_free (libexec_binary);
1261   peer->ports = ports;          /* Free in peer_destroy */
1262   peer->nports = nports;
1263   return peer;
1264
1265  err_ret:
1266   GNUNET_free_non_null (ss_instances);
1267   GNUNET_free_non_null (ports);
1268   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1269   if (NULL != emsg)
1270     *emsg = emsg_;
1271   else
1272     GNUNET_free (emsg_);
1273   return NULL;
1274 }
1275
1276
1277 /**
1278  * Obtain the peer identity from a peer handle.
1279  *
1280  * @param peer peer handle for which we want the peer's identity
1281  * @param id identifier for the daemon, will be set
1282  */
1283 void
1284 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1285                                   struct GNUNET_PeerIdentity *id)
1286 {
1287   if (NULL != peer->id)
1288   {
1289     memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1290     return;
1291   }
1292   peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1293   GNUNET_free (GNUNET_TESTING_hostkey_get (peer->system,
1294                                                           peer->key_number,
1295                                                           peer->id));
1296   memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1297 }
1298
1299
1300 /**
1301  * Start the peer. 
1302  *
1303  * @param peer peer to start
1304  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1305  */
1306 int
1307 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1308 {
1309   struct SharedServiceInstance *i;
1310   unsigned int cnt;
1311
1312   if (NULL != peer->main_process)
1313   {
1314     GNUNET_break (0);
1315     return GNUNET_SYSERR;
1316   }  
1317   GNUNET_assert (NULL != peer->cfgfile);
1318   for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1319   {
1320     i = peer->ss_instances[cnt];
1321     if ((0 == i->n_refs)
1322         && (GNUNET_SYSERR == start_shared_service_instance (i)) )
1323       return GNUNET_SYSERR;
1324     i->n_refs++;
1325   }
1326   peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL, 
1327                                                 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1328                                                 NULL, NULL,
1329                                                 peer->main_binary,
1330                                                 peer->main_binary,
1331                                                 peer->args,
1332                                                 "-c",
1333                                                 peer->cfgfile,
1334                                                 NULL);
1335   if (NULL == peer->main_process)
1336   {
1337     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1338                 _("Failed to start `%s': %s\n"),
1339                 peer->main_binary,
1340                 STRERROR (errno));
1341     return GNUNET_SYSERR;
1342   }
1343   return GNUNET_OK;
1344 }
1345
1346
1347 /**
1348  * Start a service at a peer using its ARM service
1349  *
1350  * @param peer the peer whose service has to be started
1351  * @param service_name name of the service to start
1352  * @param timeout how long should the ARM API try to send the request to start
1353  *          the service
1354  * @param cont the callback to call with result and status from ARM API
1355  * @param cont_cls the closure for the above callback
1356  * @return GNUNET_OK upon successfully queuing the service start request;
1357  *           GNUNET_SYSERR upon error
1358  */
1359 int
1360 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1361                                    const char *service_name,
1362                                    struct GNUNET_TIME_Relative timeout,
1363                                    GNUNET_ARM_ResultCallback cont,
1364                                    void *cont_cls)
1365 {
1366   if (NULL == peer->ah)
1367     return GNUNET_SYSERR;
1368   GNUNET_ARM_request_service_start (peer->ah,
1369                                     service_name,
1370                                     GNUNET_OS_INHERIT_STD_ALL,
1371                                     timeout,
1372                                     cont, cont_cls);
1373   return GNUNET_OK;
1374 }
1375
1376
1377 /**
1378  * Stop a service at a peer using its ARM service
1379  *
1380  * @param peer the peer whose service has to be stopped
1381  * @param service_name name of the service to stop
1382  * @param timeout how long should the ARM API try to send the request to stop
1383  *          the service
1384  * @param cont the callback to call with result and status from ARM API
1385  * @param cont_cls the closure for the above callback
1386  * @return GNUNET_OK upon successfully queuing the service stop request;
1387  *           GNUNET_SYSERR upon error
1388  */
1389 int 
1390 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1391                                   const char *service_name,
1392                                   struct GNUNET_TIME_Relative timeout,
1393                                   GNUNET_ARM_ResultCallback cont,
1394                                   void *cont_cls)
1395 {
1396   if (NULL == peer->ah)
1397     return GNUNET_SYSERR;
1398   GNUNET_ARM_request_service_stop (peer->ah, 
1399                                    service_name,
1400                                    timeout,
1401                                    cont, cont_cls);
1402   return GNUNET_OK;
1403 }
1404                                        
1405
1406 /**
1407  * Sends SIGTERM to the peer's main process
1408  *
1409  * @param peer the handle to the peer
1410  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1411  *           or upon any error while sending SIGTERM
1412  */
1413 int
1414 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1415 {
1416   struct SharedServiceInstance *i;
1417   unsigned int cnt;
1418
1419   if (NULL == peer->main_process)
1420   {
1421     GNUNET_break (0);
1422     return GNUNET_SYSERR;
1423   }
1424   if (0 != GNUNET_OS_process_kill (peer->main_process, SIGTERM))
1425     return GNUNET_SYSERR;
1426   for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1427   {
1428     i = peer->ss_instances[cnt];
1429     GNUNET_assert (0 != i->n_refs);
1430     i->n_refs--;
1431     if (0 == i->n_refs)
1432       stop_shared_service_instance (i);
1433   }
1434   return GNUNET_OK;
1435 }
1436
1437
1438 /**
1439  * Waits for a peer to terminate. The peer's main process will also be destroyed.
1440  *
1441  * @param peer the handle to the peer
1442  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1443  *           or upon any error while waiting
1444  */
1445 int
1446 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1447 {
1448   int ret;
1449
1450   if (NULL == peer->main_process)
1451   {
1452     GNUNET_break (0);
1453     return GNUNET_SYSERR;
1454   }
1455   ret = GNUNET_OS_process_wait (peer->main_process);
1456   GNUNET_OS_process_destroy (peer->main_process);
1457   peer->main_process = NULL;
1458   return ret;
1459 }
1460
1461
1462 /**
1463  * Stop the peer. 
1464  *
1465  * @param peer peer to stop
1466  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1467  */
1468 int
1469 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1470 {
1471   if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1472     return GNUNET_SYSERR;
1473   if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1474     return GNUNET_SYSERR;
1475   return GNUNET_OK;
1476 }
1477
1478
1479 /**
1480  * Function called whenever we connect to or disconnect from ARM.
1481  *
1482  * @param cls closure
1483  * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1484  *                  GNUNET_SYSERR on error.
1485  */
1486 static void
1487 disconn_status (void *cls, 
1488                 int connected)
1489 {
1490   struct GNUNET_TESTING_Peer *peer = cls;
1491
1492   if (GNUNET_SYSERR == connected)
1493   {
1494     peer->cb (peer->cb_cls, peer, connected);
1495     return;
1496   }
1497   if (GNUNET_YES == connected)
1498   {
1499     GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1500     return;
1501   }
1502   GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1503   GNUNET_ARM_disconnect_and_free (peer->ah);
1504   peer->ah = NULL;
1505   peer->cb (peer->cb_cls, peer, GNUNET_YES);
1506 }
1507
1508
1509 /**
1510  * Stop a peer asynchronously using ARM API.  Peer's shutdown is signaled
1511  * through the GNUNET_TESTING_PeerStopCallback().
1512  *
1513  * @param peer the peer to stop
1514  * @param cb the callback to signal peer shutdown
1515  * @param cb_cls closure for the above callback
1516  * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1517  *           does not mean that the peer is successfully stopped); GNUNET_SYSERR
1518  *           upon any error.
1519  */
1520 int
1521 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1522                                 GNUNET_TESTING_PeerStopCallback cb,
1523                                 void *cb_cls)
1524 {
1525   if (NULL == peer->main_process)
1526     return GNUNET_SYSERR;  
1527   peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1528   if (NULL == peer->ah)
1529     return GNUNET_SYSERR;
1530   peer->cb = cb;
1531   peer->cb_cls = cb_cls;
1532   return GNUNET_OK;
1533 }
1534
1535
1536 /**
1537  * Cancel a previous asynchronous peer stop request.
1538  * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1539  * peer.  It is an error to call this function if the peer stop callback was
1540  * already called
1541  *
1542  * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1543  *          before.
1544  */
1545 void
1546 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1547 {  
1548   GNUNET_assert (NULL != peer->ah);
1549   GNUNET_ARM_disconnect_and_free (peer->ah);
1550   peer->ah = NULL;
1551 }
1552
1553
1554 /**
1555  * Destroy the peer.  Releases resources locked during peer configuration.
1556  * If the peer is still running, it will be stopped AND a warning will be
1557  * printed (users of the API should stop the peer explicitly first).
1558  *
1559  * @param peer peer to destroy
1560  */
1561 void
1562 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1563 {
1564   unsigned int cnt;
1565
1566   if (NULL != peer->main_process)
1567     GNUNET_TESTING_peer_stop (peer);
1568   if (NULL != peer->ah)
1569     GNUNET_ARM_disconnect_and_free (peer->ah);
1570   if (NULL != peer->mh)
1571     GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1572   GNUNET_free (peer->cfgfile);
1573   if (NULL != peer->cfg)
1574     GNUNET_CONFIGURATION_destroy (peer->cfg);
1575   GNUNET_free (peer->main_binary);
1576   GNUNET_free (peer->args);
1577   GNUNET_free_non_null (peer->id);
1578   GNUNET_free_non_null (peer->ss_instances);
1579   if (NULL != peer->ports)
1580   {
1581     for (cnt = 0; cnt < peer->nports; cnt++)
1582       GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1583     GNUNET_free (peer->ports);
1584   }
1585   GNUNET_free (peer);
1586 }
1587
1588
1589 /**
1590  * Start a single peer and run a test using the testing library.
1591  * Starts a peer using the given configuration and then invokes the
1592  * given callback.  This function ALSO initializes the scheduler loop
1593  * and should thus be called directly from "main".  The testcase
1594  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1595  *
1596  * @param testdir only the directory name without any path. This is used for
1597  *          all service homes; the directory will be created in a temporary
1598  *          location depending on the underlying OS
1599  * @param cfgfilename name of the configuration file to use;
1600  *         use NULL to only run with defaults
1601  * @param tm main function of the testcase
1602  * @param tm_cls closure for 'tm'
1603  * @return 0 on success, 1 on error
1604  */
1605 int
1606 GNUNET_TESTING_peer_run (const char *testdir,
1607                          const char *cfgfilename,
1608                          GNUNET_TESTING_TestMain tm,
1609                          void *tm_cls)
1610 {
1611   return GNUNET_TESTING_service_run (testdir, "arm",
1612                                      cfgfilename, tm, tm_cls);
1613 }
1614
1615
1616 /**
1617  * Structure for holding service data
1618  */
1619 struct ServiceContext
1620 {
1621   /**
1622    * The configuration of the peer in which the service is run
1623    */
1624   const struct GNUNET_CONFIGURATION_Handle *cfg;
1625
1626   /**
1627    * Callback to signal service startup
1628    */
1629   GNUNET_TESTING_TestMain tm;
1630   
1631   /**
1632    * The peer in which the service is run.
1633    */
1634   struct GNUNET_TESTING_Peer *peer;
1635
1636   /**
1637    * Closure for the above callback
1638    */
1639   void *tm_cls;
1640 };
1641
1642
1643 /**
1644  * Callback to be called when SCHEDULER has been started
1645  *
1646  * @param cls the ServiceContext
1647  * @param tc the TaskContext
1648  */
1649 static void
1650 service_run_main (void *cls,
1651                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1652 {
1653   struct ServiceContext *sc = cls;
1654
1655   sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1656 }
1657
1658
1659 /**
1660  * Start a single service (no ARM, except of course if the given
1661  * service name is 'arm') and run a test using the testing library.
1662  * Starts a service using the given configuration and then invokes the
1663  * given callback.  This function ALSO initializes the scheduler loop
1664  * and should thus be called directly from "main".  The testcase
1665  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1666  *
1667  * This function is useful if the testcase is for a single service
1668  * and if that service doesn't itself depend on other services.
1669  *
1670  * @param testdir only the directory name without any path. This is used for
1671  *          all service homes; the directory will be created in a temporary
1672  *          location depending on the underlying OS
1673  * @param service_name name of the service to run
1674  * @param cfgfilename name of the configuration file to use;
1675  *         use NULL to only run with defaults
1676  * @param tm main function of the testcase
1677  * @param tm_cls closure for 'tm'
1678  * @return 0 on success, 1 on error
1679  */
1680 int
1681 GNUNET_TESTING_service_run (const char *testdir,
1682                             const char *service_name,
1683                             const char *cfgfilename,
1684                             GNUNET_TESTING_TestMain tm,
1685                             void *tm_cls)
1686 {
1687   struct ServiceContext sc;
1688   struct GNUNET_TESTING_System *system;
1689   struct GNUNET_TESTING_Peer *peer;
1690   struct GNUNET_CONFIGURATION_Handle *cfg;
1691   char *binary;
1692   char *libexec_binary;
1693
1694   GNUNET_log_setup (testdir, "WARNING", NULL);
1695   system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1696   if (NULL == system)
1697     return 1;
1698   cfg = GNUNET_CONFIGURATION_create ();
1699   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1700   {
1701     LOG (GNUNET_ERROR_TYPE_ERROR,
1702          _("Failed to load configuration from %s\n"), cfgfilename);
1703     GNUNET_CONFIGURATION_destroy (cfg);
1704     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1705     return 1;
1706   }
1707   peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1708   if (NULL == peer)
1709   {
1710     GNUNET_CONFIGURATION_destroy (cfg);
1711     hostkeys_unload (system);
1712     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1713     return 1;
1714   }
1715   GNUNET_free (peer->main_binary);
1716   GNUNET_free (peer->args);
1717   GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1718   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1719   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1720   {
1721     /* No prefix */
1722     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1723     peer->args = strdup ("");
1724   }
1725   else
1726     peer->args = strdup (libexec_binary);
1727
1728   GNUNET_free (libexec_binary);
1729   GNUNET_free (binary);
1730   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1731   {    
1732     GNUNET_TESTING_peer_destroy (peer);
1733     GNUNET_CONFIGURATION_destroy (cfg);
1734     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1735     return 1;
1736   }
1737   sc.cfg = cfg;
1738   sc.tm = tm;
1739   sc.tm_cls = tm_cls;
1740   sc.peer = peer;
1741   GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1742   if ((NULL != peer->main_process) &&
1743       (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1744   {
1745     GNUNET_TESTING_peer_destroy (peer);
1746     GNUNET_CONFIGURATION_destroy (cfg);
1747     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1748     return 1;
1749   }
1750   GNUNET_TESTING_peer_destroy (peer);
1751   GNUNET_CONFIGURATION_destroy (cfg);
1752   GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1753   return 0;
1754 }
1755
1756
1757 /**
1758  * Sometimes we use the binary name to determine which specific
1759  * test to run.  In those cases, the string after the last "_"
1760  * in 'argv[0]' specifies a string that determines the configuration
1761  * file or plugin to use.  
1762  *
1763  * This function returns the respective substring, taking care
1764  * of issues such as binaries ending in '.exe' on W32.
1765  *
1766  * @param argv0 the name of the binary
1767  * @return string between the last '_' and the '.exe' (or the end of the string),
1768  *         NULL if argv0 has no '_' 
1769  */
1770 char *
1771 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1772 {
1773   size_t slen = strlen (argv0) + 1;
1774   char sbuf[slen];
1775   char *ret;
1776   char *dot;
1777
1778   memcpy (sbuf, argv0, slen);
1779   ret = strrchr (sbuf, '_');
1780   if (NULL == ret)
1781     return NULL;
1782   ret++; /* skip underscore */
1783   dot = strchr (ret, '.');
1784   if (NULL != dot)
1785     *dot = '\0';
1786   return GNUNET_strdup (ret);
1787 }
1788
1789
1790 /* end of testing.c */