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