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