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