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