9d54b4c5349df58a61b1b5cc08c6627940ac111e
[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   {
1257     peer->main_binary = GNUNET_CONFIGURATION_expand_dollar (peer->cfg, peer->main_binary);
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_process = do_start_process (PIPE_CONTROL,
1329                                          GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1330                                          NULL,
1331                                          peer->main_binary,
1332                                          peer->args,
1333                                          "-c",
1334                                          peer->cfgfile,
1335                                          NULL);
1336   if (NULL == peer->main_process)
1337   {
1338     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1339                 _("Failed to start `%s': %s\n"),
1340                 peer->main_binary,
1341                 STRERROR (errno));
1342     return GNUNET_SYSERR;
1343   }
1344   return GNUNET_OK;
1345 }
1346
1347
1348 /**
1349  * Start a service at a peer using its ARM service
1350  *
1351  * @param peer the peer whose service has to be started
1352  * @param service_name name of the service to start
1353  * @param timeout how long should the ARM API try to send the request to start
1354  *          the service
1355  * @param cont the callback to call with result and status from ARM API
1356  * @param cont_cls the closure for the above callback
1357  * @return GNUNET_OK upon successfully queuing the service start request;
1358  *           GNUNET_SYSERR upon error
1359  */
1360 int
1361 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1362                                    const char *service_name,
1363                                    struct GNUNET_TIME_Relative timeout,
1364                                    GNUNET_ARM_ResultCallback cont,
1365                                    void *cont_cls)
1366 {
1367   if (NULL == peer->ah)
1368     return GNUNET_SYSERR;
1369   GNUNET_ARM_request_service_start (peer->ah,
1370                                     service_name,
1371                                     GNUNET_OS_INHERIT_STD_ALL,
1372                                     timeout,
1373                                     cont, cont_cls);
1374   return GNUNET_OK;
1375 }
1376
1377
1378 /**
1379  * Stop a service at a peer using its ARM service
1380  *
1381  * @param peer the peer whose service has to be stopped
1382  * @param service_name name of the service to stop
1383  * @param timeout how long should the ARM API try to send the request to stop
1384  *          the service
1385  * @param cont the callback to call with result and status from ARM API
1386  * @param cont_cls the closure for the above callback
1387  * @return GNUNET_OK upon successfully queuing the service stop request;
1388  *           GNUNET_SYSERR upon error
1389  */
1390 int
1391 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1392                                   const char *service_name,
1393                                   struct GNUNET_TIME_Relative timeout,
1394                                   GNUNET_ARM_ResultCallback cont,
1395                                   void *cont_cls)
1396 {
1397   if (NULL == peer->ah)
1398     return GNUNET_SYSERR;
1399   GNUNET_ARM_request_service_stop (peer->ah,
1400                                    service_name,
1401                                    timeout,
1402                                    cont, cont_cls);
1403   return GNUNET_OK;
1404 }
1405
1406
1407 /**
1408  * Sends SIGTERM to the peer's main process
1409  *
1410  * @param peer the handle to the peer
1411  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1412  *           or upon any error while sending SIGTERM
1413  */
1414 int
1415 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1416 {
1417   struct SharedServiceInstance *i;
1418   unsigned int cnt;
1419
1420   if (NULL == peer->main_process)
1421   {
1422     GNUNET_break (0);
1423     return GNUNET_SYSERR;
1424   }
1425   if (0 != GNUNET_OS_process_kill (peer->main_process, GNUNET_TERM_SIG))
1426     return GNUNET_SYSERR;
1427   for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1428   {
1429     i = peer->ss_instances[cnt];
1430     GNUNET_assert (0 != i->n_refs);
1431     i->n_refs--;
1432     if (0 == i->n_refs)
1433       stop_shared_service_instance (i);
1434   }
1435   return GNUNET_OK;
1436 }
1437
1438
1439 /**
1440  * Waits for a peer to terminate. The peer's main process will also be destroyed.
1441  *
1442  * @param peer the handle to the peer
1443  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1444  *           or upon any error while waiting
1445  */
1446 int
1447 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1448 {
1449   int ret;
1450
1451   if (NULL == peer->main_process)
1452   {
1453     GNUNET_break (0);
1454     return GNUNET_SYSERR;
1455   }
1456   ret = GNUNET_OS_process_wait (peer->main_process);
1457   GNUNET_OS_process_destroy (peer->main_process);
1458   peer->main_process = NULL;
1459   return ret;
1460 }
1461
1462
1463 /**
1464  * Stop the peer.
1465  *
1466  * @param peer peer to stop
1467  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1468  */
1469 int
1470 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1471 {
1472   if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1473     return GNUNET_SYSERR;
1474   if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1475     return GNUNET_SYSERR;
1476   return GNUNET_OK;
1477 }
1478
1479
1480 /**
1481  * Function called whenever we connect to or disconnect from ARM.
1482  *
1483  * @param cls closure
1484  * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1485  *                  GNUNET_SYSERR on error.
1486  */
1487 static void
1488 disconn_status (void *cls,
1489                 int connected)
1490 {
1491   struct GNUNET_TESTING_Peer *peer = cls;
1492
1493   if (GNUNET_SYSERR == connected)
1494   {
1495     peer->cb (peer->cb_cls, peer, connected);
1496     return;
1497   }
1498   if (GNUNET_YES == connected)
1499   {
1500     GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1501     return;
1502   }
1503   GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1504   GNUNET_ARM_disconnect_and_free (peer->ah);
1505   peer->ah = NULL;
1506   peer->cb (peer->cb_cls, peer, GNUNET_YES);
1507 }
1508
1509
1510 /**
1511  * Stop a peer asynchronously using ARM API.  Peer's shutdown is signaled
1512  * through the GNUNET_TESTING_PeerStopCallback().
1513  *
1514  * @param peer the peer to stop
1515  * @param cb the callback to signal peer shutdown
1516  * @param cb_cls closure for the above callback
1517  * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1518  *           does not mean that the peer is successfully stopped); GNUNET_SYSERR
1519  *           upon any error.
1520  */
1521 int
1522 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1523                                 GNUNET_TESTING_PeerStopCallback cb,
1524                                 void *cb_cls)
1525 {
1526   if (NULL == peer->main_process)
1527     return GNUNET_SYSERR;
1528   peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1529   if (NULL == peer->ah)
1530     return GNUNET_SYSERR;
1531   peer->cb = cb;
1532   peer->cb_cls = cb_cls;
1533   return GNUNET_OK;
1534 }
1535
1536
1537 /**
1538  * Cancel a previous asynchronous peer stop request.
1539  * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1540  * peer.  It is an error to call this function if the peer stop callback was
1541  * already called
1542  *
1543  * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1544  *          before.
1545  */
1546 void
1547 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1548 {
1549   GNUNET_assert (NULL != peer->ah);
1550   GNUNET_ARM_disconnect_and_free (peer->ah);
1551   peer->ah = NULL;
1552 }
1553
1554
1555 /**
1556  * Destroy the peer.  Releases resources locked during peer configuration.
1557  * If the peer is still running, it will be stopped AND a warning will be
1558  * printed (users of the API should stop the peer explicitly first).
1559  *
1560  * @param peer peer to destroy
1561  */
1562 void
1563 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1564 {
1565   unsigned int cnt;
1566
1567   if (NULL != peer->main_process)
1568     GNUNET_TESTING_peer_stop (peer);
1569   if (NULL != peer->ah)
1570     GNUNET_ARM_disconnect_and_free (peer->ah);
1571   if (NULL != peer->mh)
1572     GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1573   GNUNET_free (peer->cfgfile);
1574   if (NULL != peer->cfg)
1575     GNUNET_CONFIGURATION_destroy (peer->cfg);
1576   GNUNET_free (peer->main_binary);
1577   GNUNET_free (peer->args);
1578   GNUNET_free_non_null (peer->id);
1579   GNUNET_free_non_null (peer->ss_instances);
1580   if (NULL != peer->ports)
1581   {
1582     for (cnt = 0; cnt < peer->nports; cnt++)
1583       GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1584     GNUNET_free (peer->ports);
1585   }
1586   GNUNET_free (peer);
1587 }
1588
1589
1590 /**
1591  * Start a single peer and run a test using the testing library.
1592  * Starts a peer using the given configuration and then invokes the
1593  * given callback.  This function ALSO initializes the scheduler loop
1594  * and should thus be called directly from "main".  The testcase
1595  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1596  *
1597  * @param testdir only the directory name without any path. This is used for
1598  *          all service homes; the directory will be created in a temporary
1599  *          location depending on the underlying OS
1600  * @param cfgfilename name of the configuration file to use;
1601  *         use NULL to only run with defaults
1602  * @param tm main function of the testcase
1603  * @param tm_cls closure for 'tm'
1604  * @return 0 on success, 1 on error
1605  */
1606 int
1607 GNUNET_TESTING_peer_run (const char *testdir,
1608                          const char *cfgfilename,
1609                          GNUNET_TESTING_TestMain tm,
1610                          void *tm_cls)
1611 {
1612   return GNUNET_TESTING_service_run (testdir, "arm",
1613                                      cfgfilename, tm, tm_cls);
1614 }
1615
1616
1617 /**
1618  * Structure for holding service data
1619  */
1620 struct ServiceContext
1621 {
1622   /**
1623    * The configuration of the peer in which the service is run
1624    */
1625   const struct GNUNET_CONFIGURATION_Handle *cfg;
1626
1627   /**
1628    * Callback to signal service startup
1629    */
1630   GNUNET_TESTING_TestMain tm;
1631
1632   /**
1633    * The peer in which the service is run.
1634    */
1635   struct GNUNET_TESTING_Peer *peer;
1636
1637   /**
1638    * Closure for the above callback
1639    */
1640   void *tm_cls;
1641 };
1642
1643
1644 /**
1645  * Callback to be called when SCHEDULER has been started
1646  *
1647  * @param cls the ServiceContext
1648  * @param tc the TaskContext
1649  */
1650 static void
1651 service_run_main (void *cls,
1652                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1653 {
1654   struct ServiceContext *sc = cls;
1655
1656   sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1657 }
1658
1659
1660 /**
1661  * Start a single service (no ARM, except of course if the given
1662  * service name is 'arm') and run a test using the testing library.
1663  * Starts a service using the given configuration and then invokes the
1664  * given callback.  This function ALSO initializes the scheduler loop
1665  * and should thus be called directly from "main".  The testcase
1666  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1667  *
1668  * This function is useful if the testcase is for a single service
1669  * and if that service doesn't itself depend on other services.
1670  *
1671  * @param testdir only the directory name without any path. This is used for
1672  *          all service homes; the directory will be created in a temporary
1673  *          location depending on the underlying OS
1674  * @param service_name name of the service to run
1675  * @param cfgfilename name of the configuration file to use;
1676  *         use NULL to only run with defaults
1677  * @param tm main function of the testcase
1678  * @param tm_cls closure for 'tm'
1679  * @return 0 on success, 1 on error
1680  */
1681 int
1682 GNUNET_TESTING_service_run (const char *testdir,
1683                             const char *service_name,
1684                             const char *cfgfilename,
1685                             GNUNET_TESTING_TestMain tm,
1686                             void *tm_cls)
1687 {
1688   struct ServiceContext sc;
1689   struct GNUNET_TESTING_System *system;
1690   struct GNUNET_TESTING_Peer *peer;
1691   struct GNUNET_CONFIGURATION_Handle *cfg;
1692   char *binary;
1693   char *libexec_binary;
1694
1695   GNUNET_log_setup (testdir, "WARNING", NULL);
1696   system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1697   if (NULL == system)
1698     return 1;
1699   cfg = GNUNET_CONFIGURATION_create ();
1700   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1701   {
1702     LOG (GNUNET_ERROR_TYPE_ERROR,
1703          _("Failed to load configuration from %s\n"), cfgfilename);
1704     GNUNET_CONFIGURATION_destroy (cfg);
1705     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1706     return 1;
1707   }
1708   peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1709   if (NULL == peer)
1710   {
1711     GNUNET_CONFIGURATION_destroy (cfg);
1712     hostkeys_unload (system);
1713     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1714     return 1;
1715   }
1716   GNUNET_free (peer->main_binary);
1717   GNUNET_free (peer->args);
1718   GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1719   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1720   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1721   {
1722     /* No prefix */
1723     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1724     peer->args = strdup ("");
1725   }
1726   else
1727     peer->args = strdup (libexec_binary);
1728
1729   GNUNET_free (libexec_binary);
1730   GNUNET_free (binary);
1731   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1732   {
1733     GNUNET_TESTING_peer_destroy (peer);
1734     GNUNET_CONFIGURATION_destroy (cfg);
1735     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1736     return 1;
1737   }
1738   sc.cfg = cfg;
1739   sc.tm = tm;
1740   sc.tm_cls = tm_cls;
1741   sc.peer = peer;
1742   GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1743   if ((NULL != peer->main_process) &&
1744       (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1745   {
1746     GNUNET_TESTING_peer_destroy (peer);
1747     GNUNET_CONFIGURATION_destroy (cfg);
1748     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1749     return 1;
1750   }
1751   GNUNET_TESTING_peer_destroy (peer);
1752   GNUNET_CONFIGURATION_destroy (cfg);
1753   GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1754   return 0;
1755 }
1756
1757
1758 /**
1759  * Sometimes we use the binary name to determine which specific
1760  * test to run.  In those cases, the string after the last "_"
1761  * in 'argv[0]' specifies a string that determines the configuration
1762  * file or plugin to use.
1763  *
1764  * This function returns the respective substring, taking care
1765  * of issues such as binaries ending in '.exe' on W32.
1766  *
1767  * @param argv0 the name of the binary
1768  * @return string between the last '_' and the '.exe' (or the end of the string),
1769  *         NULL if argv0 has no '_'
1770  */
1771 char *
1772 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1773 {
1774   size_t slen = strlen (argv0) + 1;
1775   char sbuf[slen];
1776   char *ret;
1777   char *dot;
1778
1779   memcpy (sbuf, argv0, slen);
1780   ret = strrchr (sbuf, '_');
1781   if (NULL == ret)
1782     return NULL;
1783   ret++; /* skip underscore */
1784   dot = strchr (ret, '.');
1785   if (NULL != dot)
1786     *dot = '\0';
1787   return GNUNET_strdup (ret);
1788 }
1789
1790
1791 /* end of testing.c */