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