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