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