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