missing check
[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_EccPublicKey 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 (private_key, &public_key);
726   GNUNET_CRYPTO_hash (&public_key,
727                       sizeof (struct GNUNET_CRYPTO_EccPublicKey),
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_CRYPTO_ecc_key_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\n"),
1205                      STRERROR (errno));
1206     goto err_ret;
1207   }
1208   if (GNUNET_TESTING_HOSTKEYFILESIZE !=
1209       GNUNET_DISK_file_write (fd, system->hostkeys_data 
1210                               + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
1211                               GNUNET_TESTING_HOSTKEYFILESIZE))
1212   {
1213     GNUNET_asprintf (&emsg_,
1214                      _("Failed to write hostkey file for peer %u: %s\n"),
1215                      (unsigned int) key_number,
1216                      STRERROR (errno));
1217     GNUNET_DISK_file_close (fd);
1218     goto err_ret;
1219   }
1220   GNUNET_DISK_file_close (fd);
1221   ss_instances = GNUNET_malloc (sizeof (struct SharedServiceInstance *)
1222                                 * system->n_shared_services);
1223   for (cnt=0; cnt < system->n_shared_services; cnt++)
1224   {
1225     ss = system->shared_services[cnt];
1226     ss_instances[cnt] = associate_shared_service (system, ss, cfg);
1227     if (NULL == ss_instances[cnt])
1228       goto err_ret;
1229   }  
1230   GNUNET_assert (GNUNET_OK ==
1231                  GNUNET_CONFIGURATION_get_value_string 
1232                  (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));  
1233   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1234   {
1235     GNUNET_asprintf (&emsg_,
1236                      _("Failed to write configuration file `%s' for peer %u: %s\n"),
1237                      config_filename,
1238                      (unsigned int) key_number,
1239                      STRERROR (errno));    
1240     GNUNET_free (config_filename);
1241     goto err_ret;
1242   }
1243   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
1244   peer->ss_instances = ss_instances;
1245   peer->cfgfile = config_filename; /* Free in peer_destroy */
1246   peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1247   libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1248   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1249   {
1250     /* No prefix */
1251     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1252     peer->args = strdup ("");
1253   }
1254   else
1255     peer->args = strdup (libexec_binary);
1256   peer->system = system;
1257   peer->key_number = key_number;
1258   GNUNET_free (libexec_binary);
1259   peer->ports = ports;          /* Free in peer_destroy */
1260   peer->nports = nports;
1261   return peer;
1262
1263  err_ret:
1264   GNUNET_free_non_null (ss_instances);
1265   GNUNET_free_non_null (ports);
1266   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1267   if (NULL != emsg)
1268     *emsg = emsg_;
1269   else
1270     GNUNET_free (emsg_);
1271   return NULL;
1272 }
1273
1274
1275 /**
1276  * Obtain the peer identity from a peer handle.
1277  *
1278  * @param peer peer handle for which we want the peer's identity
1279  * @param id identifier for the daemon, will be set
1280  */
1281 void
1282 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1283                                   struct GNUNET_PeerIdentity *id)
1284 {
1285   if (NULL != peer->id)
1286   {
1287     memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1288     return;
1289   }
1290   peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1291   GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1292                                                           peer->key_number,
1293                                                           peer->id));
1294   memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1295 }
1296
1297
1298 /**
1299  * Start the peer. 
1300  *
1301  * @param peer peer to start
1302  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1303  */
1304 int
1305 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1306 {
1307   struct SharedServiceInstance *i;
1308   unsigned int cnt;
1309
1310   if (NULL != peer->main_process)
1311   {
1312     GNUNET_break (0);
1313     return GNUNET_SYSERR;
1314   }  
1315   GNUNET_assert (NULL != peer->cfgfile);
1316   for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1317   {
1318     i = peer->ss_instances[cnt];
1319     if ((0 == i->n_refs)
1320         && (GNUNET_SYSERR == start_shared_service_instance (i)) )
1321       return GNUNET_SYSERR;
1322     i->n_refs++;
1323   }
1324   peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL, 
1325                                                 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1326                                                 NULL, NULL,
1327                                                 peer->main_binary,
1328                                                 peer->main_binary,
1329                                                 peer->args,
1330                                                 "-c",
1331                                                 peer->cfgfile,
1332                                                 NULL);
1333   if (NULL == peer->main_process)
1334   {
1335     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1336                 _("Failed to start `%s': %s\n"),
1337                 peer->main_binary,
1338                 STRERROR (errno));
1339     return GNUNET_SYSERR;
1340   }
1341   return GNUNET_OK;
1342 }
1343
1344
1345 /**
1346  * Start a service at a peer using its ARM service
1347  *
1348  * @param peer the peer whose service has to be started
1349  * @param service_name name of the service to start
1350  * @param timeout how long should the ARM API try to send the request to start
1351  *          the service
1352  * @param cont the callback to call with result and status from ARM API
1353  * @param cont_cls the closure for the above callback
1354  * @return GNUNET_OK upon successfully queuing the service start request;
1355  *           GNUNET_SYSERR upon error
1356  */
1357 int
1358 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1359                                    const char *service_name,
1360                                    struct GNUNET_TIME_Relative timeout,
1361                                    GNUNET_ARM_ResultCallback cont,
1362                                    void *cont_cls)
1363 {
1364   if (NULL == peer->ah)
1365     return GNUNET_SYSERR;
1366   GNUNET_ARM_request_service_start (peer->ah,
1367                                     service_name,
1368                                     GNUNET_OS_INHERIT_STD_ALL,
1369                                     timeout,
1370                                     cont, cont_cls);
1371   return GNUNET_OK;
1372 }
1373
1374
1375 /**
1376  * Stop a service at a peer using its ARM service
1377  *
1378  * @param peer the peer whose service has to be stopped
1379  * @param service_name name of the service to stop
1380  * @param timeout how long should the ARM API try to send the request to stop
1381  *          the service
1382  * @param cont the callback to call with result and status from ARM API
1383  * @param cont_cls the closure for the above callback
1384  * @return GNUNET_OK upon successfully queuing the service stop request;
1385  *           GNUNET_SYSERR upon error
1386  */
1387 int 
1388 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1389                                   const char *service_name,
1390                                   struct GNUNET_TIME_Relative timeout,
1391                                   GNUNET_ARM_ResultCallback cont,
1392                                   void *cont_cls)
1393 {
1394   if (NULL == peer->ah)
1395     return GNUNET_SYSERR;
1396   GNUNET_ARM_request_service_stop (peer->ah, 
1397                                    service_name,
1398                                    timeout,
1399                                    cont, cont_cls);
1400   return GNUNET_OK;
1401 }
1402                                        
1403
1404 /**
1405  * Sends SIGTERM to the peer's main process
1406  *
1407  * @param peer the handle to the peer
1408  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1409  *           or upon any error while sending SIGTERM
1410  */
1411 int
1412 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1413 {
1414   struct SharedServiceInstance *i;
1415   unsigned int cnt;
1416
1417   if (NULL == peer->main_process)
1418   {
1419     GNUNET_break (0);
1420     return GNUNET_SYSERR;
1421   }
1422   if (0 != GNUNET_OS_process_kill (peer->main_process, SIGTERM))
1423     return GNUNET_SYSERR;
1424   for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1425   {
1426     i = peer->ss_instances[cnt];
1427     GNUNET_assert (0 != i->n_refs);
1428     i->n_refs--;
1429     if (0 == i->n_refs)
1430       stop_shared_service_instance (i);
1431   }
1432   return GNUNET_OK;
1433 }
1434
1435
1436 /**
1437  * Waits for a peer to terminate. The peer's main process will also be destroyed.
1438  *
1439  * @param peer the handle to the peer
1440  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1441  *           or upon any error while waiting
1442  */
1443 int
1444 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1445 {
1446   int ret;
1447
1448   if (NULL == peer->main_process)
1449   {
1450     GNUNET_break (0);
1451     return GNUNET_SYSERR;
1452   }
1453   ret = GNUNET_OS_process_wait (peer->main_process);
1454   GNUNET_OS_process_destroy (peer->main_process);
1455   peer->main_process = NULL;
1456   return ret;
1457 }
1458
1459
1460 /**
1461  * Stop the peer. 
1462  *
1463  * @param peer peer to stop
1464  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1465  */
1466 int
1467 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1468 {
1469   if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1470     return GNUNET_SYSERR;
1471   if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1472     return GNUNET_SYSERR;
1473   return GNUNET_OK;
1474 }
1475
1476
1477 /**
1478  * Function called whenever we connect to or disconnect from ARM.
1479  *
1480  * @param cls closure
1481  * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1482  *                  GNUNET_SYSERR on error.
1483  */
1484 static void
1485 disconn_status (void *cls, 
1486                 int connected)
1487 {
1488   struct GNUNET_TESTING_Peer *peer = cls;
1489
1490   if (GNUNET_SYSERR == connected)
1491   {
1492     peer->cb (peer->cb_cls, peer, connected);
1493     return;
1494   }
1495   if (GNUNET_YES == connected)
1496   {
1497     GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1498     return;
1499   }
1500   GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1501   GNUNET_ARM_disconnect_and_free (peer->ah);
1502   peer->ah = NULL;
1503   peer->cb (peer->cb_cls, peer, GNUNET_YES);
1504 }
1505
1506
1507 /**
1508  * Stop a peer asynchronously using ARM API.  Peer's shutdown is signaled
1509  * through the GNUNET_TESTING_PeerStopCallback().
1510  *
1511  * @param peer the peer to stop
1512  * @param cb the callback to signal peer shutdown
1513  * @param cb_cls closure for the above callback
1514  * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1515  *           does not mean that the peer is successfully stopped); GNUNET_SYSERR
1516  *           upon any error.
1517  */
1518 int
1519 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1520                                 GNUNET_TESTING_PeerStopCallback cb,
1521                                 void *cb_cls)
1522 {
1523   if (NULL == peer->main_process)
1524     return GNUNET_SYSERR;  
1525   peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1526   if (NULL == peer->ah)
1527     return GNUNET_SYSERR;
1528   peer->cb = cb;
1529   peer->cb_cls = cb_cls;
1530   return GNUNET_OK;
1531 }
1532
1533
1534 /**
1535  * Cancel a previous asynchronous peer stop request.
1536  * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1537  * peer.  It is an error to call this function if the peer stop callback was
1538  * already called
1539  *
1540  * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1541  *          before.
1542  */
1543 void
1544 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1545 {  
1546   GNUNET_assert (NULL != peer->ah);
1547   GNUNET_ARM_disconnect_and_free (peer->ah);
1548   peer->ah = NULL;
1549 }
1550
1551
1552 /**
1553  * Destroy the peer.  Releases resources locked during peer configuration.
1554  * If the peer is still running, it will be stopped AND a warning will be
1555  * printed (users of the API should stop the peer explicitly first).
1556  *
1557  * @param peer peer to destroy
1558  */
1559 void
1560 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1561 {
1562   unsigned int cnt;
1563
1564   if (NULL != peer->main_process)
1565     GNUNET_TESTING_peer_stop (peer);
1566   if (NULL != peer->ah)
1567     GNUNET_ARM_disconnect_and_free (peer->ah);
1568   if (NULL != peer->mh)
1569     GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1570   GNUNET_free (peer->cfgfile);
1571   if (NULL != peer->cfg)
1572     GNUNET_CONFIGURATION_destroy (peer->cfg);
1573   GNUNET_free (peer->main_binary);
1574   GNUNET_free (peer->args);
1575   GNUNET_free_non_null (peer->id);
1576   GNUNET_free_non_null (peer->ss_instances);
1577   if (NULL != peer->ports)
1578   {
1579     for (cnt = 0; cnt < peer->nports; cnt++)
1580       GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1581     GNUNET_free (peer->ports);
1582   }
1583   GNUNET_free (peer);
1584 }
1585
1586
1587 /**
1588  * Start a single peer and run a test using the testing library.
1589  * Starts a peer using the given configuration and then invokes the
1590  * given callback.  This function ALSO initializes the scheduler loop
1591  * and should thus be called directly from "main".  The testcase
1592  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1593  *
1594  * @param testdir only the directory name without any path. This is used for
1595  *          all service homes; the directory will be created in a temporary
1596  *          location depending on the underlying OS
1597  * @param cfgfilename name of the configuration file to use;
1598  *         use NULL to only run with defaults
1599  * @param tm main function of the testcase
1600  * @param tm_cls closure for 'tm'
1601  * @return 0 on success, 1 on error
1602  */
1603 int
1604 GNUNET_TESTING_peer_run (const char *testdir,
1605                          const char *cfgfilename,
1606                          GNUNET_TESTING_TestMain tm,
1607                          void *tm_cls)
1608 {
1609   return GNUNET_TESTING_service_run (testdir, "arm",
1610                                      cfgfilename, tm, tm_cls);
1611 }
1612
1613
1614 /**
1615  * Structure for holding service data
1616  */
1617 struct ServiceContext
1618 {
1619   /**
1620    * The configuration of the peer in which the service is run
1621    */
1622   const struct GNUNET_CONFIGURATION_Handle *cfg;
1623
1624   /**
1625    * Callback to signal service startup
1626    */
1627   GNUNET_TESTING_TestMain tm;
1628   
1629   /**
1630    * The peer in which the service is run.
1631    */
1632   struct GNUNET_TESTING_Peer *peer;
1633
1634   /**
1635    * Closure for the above callback
1636    */
1637   void *tm_cls;
1638 };
1639
1640
1641 /**
1642  * Callback to be called when SCHEDULER has been started
1643  *
1644  * @param cls the ServiceContext
1645  * @param tc the TaskContext
1646  */
1647 static void
1648 service_run_main (void *cls,
1649                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1650 {
1651   struct ServiceContext *sc = cls;
1652
1653   sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1654 }
1655
1656
1657 /**
1658  * Start a single service (no ARM, except of course if the given
1659  * service name is 'arm') and run a test using the testing library.
1660  * Starts a service using the given configuration and then invokes the
1661  * given callback.  This function ALSO initializes the scheduler loop
1662  * and should thus be called directly from "main".  The testcase
1663  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1664  *
1665  * This function is useful if the testcase is for a single service
1666  * and if that service doesn't itself depend on other services.
1667  *
1668  * @param testdir only the directory name without any path. This is used for
1669  *          all service homes; the directory will be created in a temporary
1670  *          location depending on the underlying OS
1671  * @param service_name name of the service to run
1672  * @param cfgfilename name of the configuration file to use;
1673  *         use NULL to only run with defaults
1674  * @param tm main function of the testcase
1675  * @param tm_cls closure for 'tm'
1676  * @return 0 on success, 1 on error
1677  */
1678 int
1679 GNUNET_TESTING_service_run (const char *testdir,
1680                             const char *service_name,
1681                             const char *cfgfilename,
1682                             GNUNET_TESTING_TestMain tm,
1683                             void *tm_cls)
1684 {
1685   struct ServiceContext sc;
1686   struct GNUNET_TESTING_System *system;
1687   struct GNUNET_TESTING_Peer *peer;
1688   struct GNUNET_CONFIGURATION_Handle *cfg;
1689   char *binary;
1690   char *libexec_binary;
1691
1692   GNUNET_log_setup (testdir, "WARNING", NULL);
1693   system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1694   if (NULL == system)
1695     return 1;
1696   cfg = GNUNET_CONFIGURATION_create ();
1697   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1698   {
1699     LOG (GNUNET_ERROR_TYPE_ERROR,
1700          _("Failed to load configuration from %s\n"), cfgfilename);
1701     GNUNET_CONFIGURATION_destroy (cfg);
1702     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1703     return 1;
1704   }
1705   peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1706   if (NULL == peer)
1707   {
1708     GNUNET_CONFIGURATION_destroy (cfg);
1709     hostkeys_unload (system);
1710     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1711     return 1;
1712   }
1713   GNUNET_free (peer->main_binary);
1714   GNUNET_free (peer->args);
1715   GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1716   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1717   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1718   {
1719     /* No prefix */
1720     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1721     peer->args = strdup ("");
1722   }
1723   else
1724     peer->args = strdup (libexec_binary);
1725
1726   GNUNET_free (libexec_binary);
1727   GNUNET_free (binary);
1728   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1729   {    
1730     GNUNET_TESTING_peer_destroy (peer);
1731     GNUNET_CONFIGURATION_destroy (cfg);
1732     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1733     return 1;
1734   }
1735   sc.cfg = cfg;
1736   sc.tm = tm;
1737   sc.tm_cls = tm_cls;
1738   sc.peer = peer;
1739   GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1740   if ((NULL != peer->main_process) &&
1741       (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1742   {
1743     GNUNET_TESTING_peer_destroy (peer);
1744     GNUNET_CONFIGURATION_destroy (cfg);
1745     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1746     return 1;
1747   }
1748   GNUNET_TESTING_peer_destroy (peer);
1749   GNUNET_CONFIGURATION_destroy (cfg);
1750   GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1751   return 0;
1752 }
1753
1754
1755 /**
1756  * Sometimes we use the binary name to determine which specific
1757  * test to run.  In those cases, the string after the last "_"
1758  * in 'argv[0]' specifies a string that determines the configuration
1759  * file or plugin to use.  
1760  *
1761  * This function returns the respective substring, taking care
1762  * of issues such as binaries ending in '.exe' on W32.
1763  *
1764  * @param argv0 the name of the binary
1765  * @return string between the last '_' and the '.exe' (or the end of the string),
1766  *         NULL if argv0 has no '_' 
1767  */
1768 char *
1769 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1770 {
1771   size_t slen = strlen (argv0) + 1;
1772   char sbuf[slen];
1773   char *ret;
1774   char *dot;
1775
1776   memcpy (sbuf, argv0, slen);
1777   ret = strrchr (sbuf, '_');
1778   if (NULL == ret)
1779     return NULL;
1780   ret++; /* skip underscore */
1781   dot = strchr (ret, '.');
1782   if (NULL != dot)
1783     *dot = '\0';
1784   return GNUNET_strdup (ret);
1785 }
1786
1787
1788 /* end of testing.c */