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