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