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