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