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