-remove unnecessary arguments from ARM callbacks
[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 /**
68  * Handle for a system on which GNUnet peers are executed;
69  * a system is used for reserving unique paths and ports.
70  */
71 struct GNUNET_TESTING_System
72 {
73   /**
74    * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
75    * SERVICEHOME.    */
76   char *tmppath;
77
78   /**
79    * The trusted ip. Can either be a single ip address or a network address in
80    * CIDR notation.
81    */
82   char *trusted_ip;
83
84   /**
85    * our hostname
86    */
87   char *hostname;
88
89   /**
90    * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
91    */
92   char *hostkeys_data;
93
94   /**
95    * Bitmap where each TCP port that has already been reserved for
96    * some GNUnet peer is recorded.  Note that we additionally need to
97    * test if a port is already in use by non-GNUnet components before
98    * assigning it to a peer/service.  If we detect that a port is
99    * already in use, we also mark it in this bitmap.  So all the bits
100    * that are zero merely indicate ports that MIGHT be available for
101    * peers.
102    */
103   uint32_t reserved_tcp_ports[65536 / 32];
104
105   /**
106    * Bitmap where each UDP port that has already been reserved for
107    * some GNUnet peer is recorded.  Note that we additionally need to
108    * test if a port is already in use by non-GNUnet components before
109    * assigning it to a peer/service.  If we detect that a port is
110    * already in use, we also mark it in this bitmap.  So all the bits
111    * that are zero merely indicate ports that MIGHT be available for
112    * peers.
113    */
114   uint32_t reserved_udp_ports[65536 / 32];
115
116   /**
117    * Counter we use to make service home paths unique on this system;
118    * the full path consists of the tmppath and this number.  Each
119    * UNIXPATH for a peer is also modified to include the respective
120    * path counter to ensure uniqueness.  This field is incremented
121    * by one for each configured peer.  Even if peers are destroyed,
122    * we never re-use path counters.
123    */
124   uint32_t path_counter;  
125
126   /**
127    * The number of hostkeys
128    */
129   uint32_t total_hostkeys;
130
131   /**
132    * Lowest port we are allowed to use.
133    */
134   uint16_t lowport;
135
136   /**
137    * Highest port we are allowed to use.
138    */
139   uint16_t highport;
140 };
141
142
143 /**
144  * Handle for a GNUnet peer controlled by testing.
145  */
146 struct GNUNET_TESTING_Peer
147 {
148   /**
149    * The TESTING system associated with this peer
150    */
151   struct GNUNET_TESTING_System *system;
152
153   /**
154    * Path to the configuration file for this peer.
155    */
156   char *cfgfile;
157
158   /**
159    * Binary to be executed during 'GNUNET_TESTING_peer_start'.
160    * Typically 'gnunet-service-arm' (but can be set to a 
161    * specific service by 'GNUNET_TESTING_service_run' if
162    * necessary).
163    */ 
164   char *main_binary;
165   char *args;
166   
167   /**
168    * Handle to the running binary of the service, NULL if the
169    * peer/service is currently not running.
170    */
171   struct GNUNET_OS_Process *main_process;
172
173   /**
174    * The handle to the peer's ARM service
175    */
176   struct GNUNET_ARM_Handle *ah;
177
178   /**
179    * Handle to ARM monitoring
180    */
181   struct GNUNET_ARM_MonitorHandle *mh;
182
183   /**
184    * The config of the peer
185    */
186   struct GNUNET_CONFIGURATION_Handle *cfg;
187
188   /**
189    * The callback to call asynchronously when a peer is stopped
190    */  
191   GNUNET_TESTING_PeerStopCallback cb;
192   
193   /**
194    * The closure for the above callback
195    */
196   void *cb_cls;
197   
198   /**
199    * The cached identity of this peer.  Will be populated on call to
200    * GNUNET_TESTING_peer_get_identity()
201    */
202   struct GNUNET_PeerIdentity *id;
203
204   /**
205    * Array of ports currently allocated to this peer.  These ports will be
206    * released upon peer destroy and can be used by other peers which are
207    * configured after.
208    */
209   uint16_t *ports;
210
211   /**
212    * The number of ports in the above array
213    */
214   unsigned int nports;
215
216   /**
217    * The keynumber of this peer's hostkey
218    */
219   uint32_t key_number;
220 };
221
222
223 /**
224  * Testing includes a number of pre-created hostkeys for faster peer
225  * startup. This function loads such keys into memory from a file.
226  *
227  * @param system the testing system handle
228  * @return GNUNET_OK on success; GNUNET_SYSERR on error
229  */
230 static int
231 hostkeys_load (struct GNUNET_TESTING_System *system)
232 {
233   uint64_t fs; 
234   char *data_dir;
235   char *filename;
236   
237   GNUNET_assert (NULL == system->hostkeys_data);
238   data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
239   GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
240   GNUNET_free (data_dir);  
241
242   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
243   {
244     LOG (GNUNET_ERROR_TYPE_ERROR,
245          _("Hostkeys file not found: %s\n"), filename);
246     GNUNET_free (filename);
247     return GNUNET_SYSERR;
248   }
249   /* Check hostkey file size, read entire thing into memory */
250   if (GNUNET_OK != 
251       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
252     fs = 0;
253   if (0 == fs)
254   {
255     GNUNET_free (filename);
256     return GNUNET_SYSERR;       /* File is empty */
257   }
258   if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
259   {
260     LOG (GNUNET_ERROR_TYPE_ERROR,
261          _("Incorrect hostkey file format: %s\n"), filename);
262     GNUNET_free (filename);
263     return GNUNET_SYSERR;
264   }
265   system->hostkeys_data = GNUNET_malloc_large ((size_t) fs);
266   if (GNUNET_DISK_fn_read (filename, system->hostkeys_data, fs) != (ssize_t) fs)
267   {
268     GNUNET_free (filename);
269     GNUNET_free (system->hostkeys_data);
270     system->hostkeys_data = NULL;
271     return GNUNET_SYSERR;
272   }
273   system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
274   GNUNET_free (filename);
275   return GNUNET_OK;
276 }
277
278
279 /**
280  * Function to remove the loaded hostkeys
281  *
282  * @param system the testing system handle
283  */
284 static void
285 hostkeys_unload (struct GNUNET_TESTING_System *system)
286 {
287   GNUNET_break (NULL != system->hostkeys_data);
288   GNUNET_free_non_null (system->hostkeys_data);
289   system->hostkeys_data = NULL;
290   system->total_hostkeys = 0;
291 }
292
293
294 /**
295  * Create a system handle.  There must only be one system
296  * handle per operating system.
297  *
298  * @param testdir only the directory name without any path. This is used for
299  *          all service homes; the directory will be created in a temporary
300  *          location depending on the underlying OS
301  * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
302  *          service configurations generated to allow control connections from
303  *          this ip. This can either be a single ip address or a network address
304  *          in CIDR notation.
305  * @param hostname the hostname of the system we are using for testing; NULL for
306  *          localhost
307  * @param lowport lowest port number this system is allowed to allocate (inclusive)
308  * @param highport highest port number this system is allowed to allocate (exclusive)
309  * @return handle to this system, NULL on error
310  */
311 struct GNUNET_TESTING_System *
312 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
313                                              const char *trusted_ip,
314                                              const char *hostname,
315                                              uint16_t lowport,
316                                              uint16_t highport)
317 {
318   struct GNUNET_TESTING_System *system;
319
320   GNUNET_assert (NULL != testdir);
321   system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
322   system->tmppath = GNUNET_DISK_mkdtemp (testdir);
323   system->lowport = lowport;
324   system->highport = highport;
325   if (NULL == system->tmppath)
326   {
327     GNUNET_free (system);
328     return NULL;
329   }
330   if (NULL != trusted_ip)
331     system->trusted_ip = GNUNET_strdup (trusted_ip);
332   if (NULL != hostname)
333     system->hostname = GNUNET_strdup (hostname);
334   if (GNUNET_OK != hostkeys_load (system))
335   {
336     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
337     return NULL;
338   }
339   return system;
340 }
341
342
343 /**
344  * Create a system handle.  There must only be one system handle per operating
345  * system.  Uses a default range for allowed ports.  Ports are still tested for
346  * availability.
347  *
348  * @param testdir only the directory name without any path. This is used for all
349  *          service homes; the directory will be created in a temporary location
350  *          depending on the underlying OS
351  * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
352  *          service configurations generated to allow control connections from
353  *          this ip. This can either be a single ip address or a network address
354  *          in CIDR notation.
355  * @param hostname the hostname of the system we are using for testing; NULL for
356  *          localhost
357  * @return handle to this system, NULL on error
358  */
359 struct GNUNET_TESTING_System *
360 GNUNET_TESTING_system_create (const char *testdir,
361                               const char *trusted_ip,
362                               const char *hostname)
363 {
364   return GNUNET_TESTING_system_create_with_portrange (testdir,
365                                                       trusted_ip,
366                                                       hostname,
367                                                       LOW_PORT,
368                                                       HIGH_PORT);
369 }
370
371
372 /**
373  * Free system resources.
374  *
375  * @param system system to be freed
376  * @param remove_paths should the 'testdir' and all subdirectories
377  *        be removed (clean up on shutdown)?
378  */
379 void
380 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
381                                int remove_paths)
382 {
383   if (NULL != system->hostkeys_data)
384     hostkeys_unload (system);
385   if (GNUNET_YES == remove_paths)
386     GNUNET_DISK_directory_remove (system->tmppath);
387   GNUNET_free (system->tmppath);
388   GNUNET_free_non_null (system->trusted_ip);
389   GNUNET_free_non_null (system->hostname);
390   GNUNET_free (system);
391 }
392
393
394 /**
395  * Reserve a TCP or UDP port for a peer.
396  *
397  * @param system system to use for reservation tracking
398  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
399  * @return 0 if no free port was available
400  */
401 uint16_t 
402 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
403                              int is_tcp)
404 {
405   struct GNUNET_NETWORK_Handle *socket;
406   struct addrinfo hint;
407   struct addrinfo *ret;
408   struct addrinfo *ai;
409   uint32_t *port_buckets;
410   char *open_port_str;
411   int bind_status;
412   uint32_t xor_image;
413   uint16_t index;
414   uint16_t open_port;
415   uint16_t pos;
416
417   /*
418   FIXME: Instead of using getaddrinfo we should try to determine the port
419          status by the following heurestics.
420   
421          On systems which support both IPv4 and IPv6, only ports open on both
422          address families are considered open.
423          On system with either IPv4 or IPv6. A port is considered open if it's
424          open in the respective address family
425   */
426   hint.ai_family = AF_UNSPEC;   /* IPv4 and IPv6 */
427   hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
428   hint.ai_protocol = 0;
429   hint.ai_addrlen = 0;
430   hint.ai_addr = NULL;
431   hint.ai_canonname = NULL;
432   hint.ai_next = NULL;
433   hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;  /* Wild card address */
434   port_buckets = (GNUNET_YES == is_tcp) ?
435     system->reserved_tcp_ports : system->reserved_udp_ports;
436   for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
437   {
438     xor_image = (UINT32_MAX ^ port_buckets[index]);
439     if (0 == xor_image)        /* Ports in the bucket are full */
440       continue;
441     pos = system->lowport % 32;
442     while (pos < 32)
443     {
444       if (0 == ((xor_image >> pos) & 1U))
445       {
446         pos++;
447         continue;
448       }
449       open_port = (index * 32) + pos;
450       if (open_port >= system->highport)
451         return 0;
452       GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
453       ret = NULL;
454       GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
455       GNUNET_free (open_port_str);
456       bind_status = GNUNET_NO;
457       for (ai = ret; NULL != ai; ai = ai->ai_next)
458       {
459         socket = GNUNET_NETWORK_socket_create (ai->ai_family,
460                                                (GNUNET_YES == is_tcp) ?
461                                                SOCK_STREAM : SOCK_DGRAM,
462                                                0);
463         if (NULL == socket)
464           continue;
465         bind_status = GNUNET_NETWORK_socket_bind (socket,
466                                                   ai->ai_addr,
467                                                   ai->ai_addrlen);
468         GNUNET_NETWORK_socket_close (socket);
469         if (GNUNET_OK != bind_status)
470           break;
471       }
472       port_buckets[index] |= (1U << pos); /* Set the port bit */
473       freeaddrinfo (ret);
474       if (GNUNET_OK == bind_status)
475       {
476         LOG (GNUNET_ERROR_TYPE_DEBUG,
477              "Found a free port %u\n", (unsigned int) open_port);
478         return open_port;
479       }
480       pos++;
481     }
482   }
483   return 0;
484 }
485
486
487 /**
488  * Release reservation of a TCP or UDP port for a peer
489  * (used during GNUNET_TESTING_peer_destroy).
490  *
491  * @param system system to use for reservation tracking
492  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
493  * @param port reserved port to release
494  */
495 void
496 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
497                              int is_tcp,
498                              uint16_t port)
499 {
500   uint32_t *port_buckets;
501   uint16_t bucket;
502   uint16_t pos;
503
504   port_buckets = (GNUNET_YES == is_tcp) ?
505     system->reserved_tcp_ports : system->reserved_udp_ports;
506   bucket = port / 32;
507   pos = port % 32;
508   LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
509   if (0 == (port_buckets[bucket] & (1U << pos)))
510   {
511     GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
512     return;
513   }
514   port_buckets[bucket] &= ~(1U << pos);
515 }
516
517
518 /**
519  * Testing includes a number of pre-created hostkeys for
520  * faster peer startup.  This function can be used to
521  * access the n-th key of those pre-created hostkeys; note
522  * that these keys are ONLY useful for testing and not
523  * secure as the private keys are part of the public 
524  * GNUnet source code.
525  *
526  * This is primarily a helper function used internally
527  * by 'GNUNET_TESTING_peer_configure'.
528  *
529  * @param system the testing system handle
530  * @param key_number desired pre-created hostkey to obtain
531  * @param id set to the peer's identity (hash of the public
532  *        key; if NULL, GNUNET_SYSERR is returned immediately
533  * @return NULL on error (not enough keys)
534  */
535 struct GNUNET_CRYPTO_EccPrivateKey *
536 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
537                             uint32_t key_number,
538                             struct GNUNET_PeerIdentity *id)
539 {  
540   struct GNUNET_CRYPTO_EccPrivateKey *private_key;
541   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
542   
543   if ((NULL == id) || (NULL == system->hostkeys_data))
544     return NULL;
545   if (key_number >= system->total_hostkeys)
546   {
547     LOG (GNUNET_ERROR_TYPE_ERROR,
548          _("Key number %u does not exist\n"), key_number);
549     return NULL;
550   }   
551   private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
552                                               (key_number *
553                                                GNUNET_TESTING_HOSTKEYFILESIZE),
554                                               GNUNET_TESTING_HOSTKEYFILESIZE,
555                                               GNUNET_NO);
556   if (NULL == private_key)
557   {
558     LOG (GNUNET_ERROR_TYPE_ERROR,
559          _("Error while decoding key %u\n"), key_number);
560     return NULL;
561   }
562   GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
563   GNUNET_CRYPTO_hash (&public_key,
564                       sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
565                       &(id->hashPubKey));
566   return private_key;
567 }
568
569
570 /**
571  * Structure for holding data to build new configurations from a configuration
572  * template
573  */
574 struct UpdateContext
575 {
576   /**
577    * The system for which we are building configurations
578    */
579   struct GNUNET_TESTING_System *system;
580   
581   /**
582    * The configuration we are building
583    */
584   struct GNUNET_CONFIGURATION_Handle *cfg;
585
586   /**
587    * The customized service home path for this peer
588    */
589   char *service_home;
590
591   /**
592    * Array of ports currently allocated to this peer.  These ports will be
593    * released upon peer destroy and can be used by other peers which are
594    * configured after.
595    */
596   uint16_t *ports;
597
598   /**
599    * The number of ports in the above array
600    */
601   unsigned int nports;
602
603   /**
604    * build status - to signal error while building a configuration
605    */
606   int status;
607 };
608
609
610 /**
611  * Function to iterate over options.  Copies
612  * the options to the target configuration,
613  * updating PORT values as needed.
614  *
615  * @param cls the UpdateContext
616  * @param section name of the section
617  * @param option name of the option
618  * @param value value of the option
619  */
620 static void
621 update_config (void *cls, const char *section, const char *option,
622                const char *value)
623 {
624   struct UpdateContext *uc = cls;
625   unsigned int ival;
626   char cval[12];
627   char uval[128];
628   char *single_variable;
629   char *per_host_variable;
630   unsigned long long num_per_host;
631   uint16_t new_port;
632
633   if (GNUNET_OK != uc->status)
634     return;
635   if (! ((0 == strcmp (option, "PORT"))
636          || (0 == strcmp (option, "UNIXPATH"))
637          || (0 == strcmp (option, "HOSTNAME"))))
638     return;
639   GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
640   GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
641   if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
642   {
643     if ((ival != 0) &&
644         (GNUNET_YES !=
645          GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
646                                                single_variable)))
647     {
648       /* FIXME: What about UDP? */
649       new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
650       if (0 == new_port)
651       {
652         uc->status = GNUNET_SYSERR;
653         GNUNET_free (single_variable);
654         GNUNET_free (per_host_variable);
655         return;
656       }
657       GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
658       value = cval;
659       GNUNET_array_append (uc->ports, uc->nports, new_port);
660     }
661     else if ((ival != 0) &&
662              (GNUNET_YES ==
663               GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
664                                                     single_variable)) &&
665              GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
666                                                     per_host_variable,
667                                                     &num_per_host))
668     {
669       /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
670       /*                  ival + ctx->fdnum % num_per_host); */
671       /* value = cval; */
672       GNUNET_break (0);         /* FIXME */
673     }
674   }
675   if (0 == strcmp (option, "UNIXPATH"))
676   {
677     if (GNUNET_YES !=
678         GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
679                                               single_variable))
680     {
681       GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
682                        uc->service_home, section);
683       value = uval;
684     }
685     else if ((GNUNET_YES ==
686               GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
687                                                      per_host_variable,
688                                                      &num_per_host)) &&
689              (num_per_host > 0))
690     {
691       GNUNET_break(0);          /* FIXME */
692     }
693   }
694   if (0 == strcmp (option, "HOSTNAME"))
695   {
696     value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
697   }
698   GNUNET_free (single_variable);
699   GNUNET_free (per_host_variable);
700   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
701 }
702
703
704 /**
705  * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
706  * 'trusted_hosts' in all sections
707  *
708  * @param cls the UpdateContext
709  * @param section name of the section
710  */
711 static void
712 update_config_sections (void *cls,
713                         const char *section)
714 {
715   struct UpdateContext *uc = cls;  
716   char **ikeys;
717   char *val;
718   char *ptr;
719   char *orig_allowed_hosts;
720   char *allowed_hosts;
721   char *ACCEPT_FROM_key;
722   uint16_t ikeys_cnt;
723   uint16_t key;
724   
725   ikeys_cnt = 0;
726   val = NULL;
727   if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
728                                                      "TESTING_IGNORE_KEYS"))
729   {
730     GNUNET_assert 
731       (GNUNET_YES == 
732        GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
733                                               "TESTING_IGNORE_KEYS", &val));
734     ptr = val;
735     for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
736       ptr++;
737     if (0 == ikeys_cnt)
738       GNUNET_break (0);
739     else
740     {
741       ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
742       ptr = val;
743       for (key = 0; key < ikeys_cnt; key++)
744       {
745         ikeys[key] = ptr;
746         ptr = strstr (ptr, ";");
747         *ptr = '\0';
748         ptr++;
749       }
750     }
751   }
752   if (0 != ikeys_cnt)
753   {
754     for (key = 0; key < ikeys_cnt; key++)
755     {
756       if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
757         break;
758     }
759     if ((key == ikeys_cnt) &&
760         (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
761                                                         "ADVERTISED_PORT")))
762     {
763       if (GNUNET_OK == 
764           GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
765       {
766         GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, 
767                                                "ADVERTISED_PORT", ptr);
768         GNUNET_free (ptr);
769       }
770     }
771     for (key = 0; key < ikeys_cnt; key++)
772     {
773       if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
774       {
775         GNUNET_free (ikeys);
776         GNUNET_free (val);
777         return;
778       }
779     }
780     GNUNET_free (ikeys);
781   }
782   GNUNET_free_non_null (val);
783   ACCEPT_FROM_key = "ACCEPT_FROM";  
784   if ((NULL != uc->system->trusted_ip) && 
785       (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
786     ACCEPT_FROM_key = "ACCEPT_FROM6";
787   if (GNUNET_OK != 
788       GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
789                                              &orig_allowed_hosts))
790   {
791     orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
792   }
793   if (NULL == uc->system->trusted_ip)
794     allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
795   else
796     GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
797                      uc->system->trusted_ip);
798   GNUNET_free (orig_allowed_hosts);
799   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
800                                          allowed_hosts);
801   GNUNET_free (allowed_hosts);  
802 }
803
804
805 /**
806  * Create a new configuration using the given configuration as a template;
807  * ports and paths will be modified to select available ports on the local
808  * system. The default configuration will be available in PATHS section under
809  * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
810  * section to the temporary directory specific to this configuration. If we run
811  * out of "*port" numbers, return SYSERR.
812  *
813  * This is primarily a helper function used internally
814  * by 'GNUNET_TESTING_peer_configure'.
815  *
816  * @param system system to use to coordinate resource usage
817  * @param cfg template configuration to update
818  * @param ports array with port numbers used in the created configuration.
819  *          Will be updated upon successful return.  Can be NULL
820  * @param nports the size of the `ports' array.  Will be updated.
821  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
822  *           be incomplete and should not be used there upon
823  */
824 static int
825 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
826                                       struct GNUNET_CONFIGURATION_Handle *cfg,
827                                       uint16_t **ports,
828                                       unsigned int *nports)
829 {
830   struct UpdateContext uc;
831   char *default_config;
832   
833   uc.system = system;
834   uc.cfg = cfg;
835   uc.status = GNUNET_OK;
836   uc.ports = NULL;
837   uc.nports = 0;
838   GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
839                    system->path_counter++);
840   GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
841   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
842                                          default_config);
843   GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
844                                          default_config);
845   GNUNET_free (default_config);
846   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
847                                          uc.service_home);
848   /* make PORTs and UNIXPATHs unique */
849   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
850   /* allow connections to services from system trusted_ip host */
851   GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
852   /* enable loopback-based connections between peers */
853   GNUNET_CONFIGURATION_set_value_string (cfg, 
854                                          "nat",
855                                          "USE_LOCALADDR", "YES");
856   GNUNET_free (uc.service_home);
857   if ((NULL != ports) && (NULL != nports))
858   {
859     *ports = uc.ports;
860     *nports = uc.nports;
861   }
862   else
863     GNUNET_free_non_null (uc.ports);
864   return uc.status;
865 }
866
867
868 /**
869  * Create a new configuration using the given configuration as a template;
870  * ports and paths will be modified to select available ports on the local
871  * system. The default configuration will be available in PATHS section under
872  * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
873  * section to the temporary directory specific to this configuration. If we run
874  * out of "*port" numbers, return SYSERR.
875  *
876  * This is primarily a helper function used internally
877  * by 'GNUNET_TESTING_peer_configure'.
878  *
879  * @param system system to use to coordinate resource usage
880  * @param cfg template configuration to update
881  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
882  *           be incomplete and should not be used there upon
883  */
884 int
885 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
886                                      struct GNUNET_CONFIGURATION_Handle *cfg)
887 {
888   return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
889 }
890
891
892 /**
893  * Configure a GNUnet peer.  GNUnet must be installed on the local
894  * system and available in the PATH. 
895  *
896  * @param system system to use to coordinate resource usage
897  * @param cfg configuration to use; will be UPDATED (to reflect needed
898  *            changes in port numbers and paths)
899  * @param key_number number of the hostkey to use for the peer
900  * @param id identifier for the daemon, will be set, can be NULL
901  * @param emsg set to freshly allocated error message (set to NULL on success), 
902  *          can be NULL
903  * @return handle to the peer, NULL on error
904  */
905 struct GNUNET_TESTING_Peer *
906 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
907                                struct GNUNET_CONFIGURATION_Handle *cfg,
908                                uint32_t key_number,
909                                struct GNUNET_PeerIdentity *id,
910                                char **emsg)
911 {
912   struct GNUNET_TESTING_Peer *peer;
913   struct GNUNET_DISK_FileHandle *fd;
914   char *service_home;  
915   char hostkey_filename[128];
916   char *config_filename;
917   char *libexec_binary;
918   char *emsg_;
919   struct GNUNET_CRYPTO_EccPrivateKey *pk;
920   uint16_t *ports;
921   unsigned int nports;      
922
923   ports = NULL;
924   nports = 0;
925   if (NULL != emsg)
926     *emsg = NULL;
927   if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
928                                                          &ports, &nports))
929   {
930     GNUNET_asprintf (&emsg_,
931                      _("Failed to create configuration for peer "
932                        "(not enough free ports?)\n"));
933     goto err_ret;
934   }
935   if (key_number >= system->total_hostkeys)
936   {
937     GNUNET_asprintf (&emsg_,
938                      _("You attempted to create a testbed with more than %u hosts.  Please precompute more hostkeys first.\n"),
939                      (unsigned int) system->total_hostkeys);    
940     goto err_ret;
941   }
942   pk = NULL;
943   if ((NULL != id) &&
944       (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
945   {
946     GNUNET_asprintf (&emsg_,
947                      _("Failed to initialize hostkey for peer %u\n"),
948                      (unsigned int) key_number);
949     goto err_ret;
950   }
951   if (NULL != pk)
952     GNUNET_CRYPTO_ecc_key_free (pk);
953   GNUNET_assert (GNUNET_OK == 
954                  GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
955                                                         "SERVICEHOME",
956                                                         &service_home));
957   /* FIXME: might be better to evaluate actual configuration option here... */
958   GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
959                    service_home);
960   GNUNET_free (service_home);
961   fd = GNUNET_DISK_file_open (hostkey_filename,
962                               GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
963                               GNUNET_DISK_PERM_USER_READ 
964                               | GNUNET_DISK_PERM_USER_WRITE);
965   if (NULL == fd)
966   {
967     GNUNET_asprintf (&emsg_, _("Cannot open hostkey file: %s\n"),
968                      STRERROR (errno));
969     goto err_ret;
970   }
971   if (GNUNET_TESTING_HOSTKEYFILESIZE !=
972       GNUNET_DISK_file_write (fd, system->hostkeys_data 
973                               + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
974                               GNUNET_TESTING_HOSTKEYFILESIZE))
975   {
976     GNUNET_asprintf (&emsg_,
977                      _("Failed to write hostkey file for peer %u: %s\n"),
978                      (unsigned int) key_number,
979                      STRERROR (errno));
980     GNUNET_DISK_file_close (fd);
981     goto err_ret;
982   }
983   GNUNET_DISK_file_close (fd);
984   GNUNET_assert (GNUNET_OK ==
985                  GNUNET_CONFIGURATION_get_value_string 
986                  (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));  
987   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
988   {
989     GNUNET_asprintf (&emsg_,
990                      _("Failed to write configuration file `%s' for peer %u: %s\n"),
991                      config_filename,
992                      (unsigned int) key_number,
993                      STRERROR (errno));    
994     GNUNET_free (config_filename);
995     goto err_ret;
996   }
997   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
998   peer->cfgfile = config_filename; /* Free in peer_destroy */
999   peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1000   libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1001   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1002   {
1003     /* No prefix */
1004     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1005     peer->args = strdup ("");
1006   }
1007   else
1008     peer->args = strdup (libexec_binary);
1009   peer->system = system;
1010   peer->key_number = key_number;
1011   GNUNET_free (libexec_binary);
1012   peer->ports = ports;          /* Free in peer_destroy */
1013   peer->nports = nports;
1014   return peer;
1015
1016  err_ret:
1017   GNUNET_free_non_null (ports);
1018   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1019   if (NULL != emsg)
1020     *emsg = emsg_;
1021   else
1022     GNUNET_free (emsg_);
1023   return NULL;
1024 }
1025
1026
1027 /**
1028  * Obtain the peer identity from a peer handle.
1029  *
1030  * @param peer peer handle for which we want the peer's identity
1031  * @param id identifier for the daemon, will be set
1032  */
1033 void
1034 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1035                                   struct GNUNET_PeerIdentity *id)
1036 {
1037   if (NULL != peer->id)
1038   {
1039     memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1040     return;
1041   }
1042   peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1043   GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1044                                                           peer->key_number,
1045                                                           peer->id));
1046   memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1047 }
1048
1049
1050 /**
1051  * Start the peer. 
1052  *
1053  * @param peer peer to start
1054  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1055  */
1056 int
1057 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1058 {
1059   if (NULL != peer->main_process)
1060   {
1061     GNUNET_break (0);
1062     return GNUNET_SYSERR;
1063   }
1064   GNUNET_assert (NULL != peer->cfgfile);
1065   peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL, 
1066                                                 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1067                                                 NULL, NULL,
1068                                                 peer->main_binary,
1069                                                 peer->main_binary,
1070                                                 peer->args,
1071                                                 "-c",
1072                                                 peer->cfgfile,
1073                                                 NULL);
1074   if (NULL == peer->main_process)
1075   {
1076     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1077                 _("Failed to start `%s': %s\n"),
1078                 peer->main_binary,
1079                 STRERROR (errno));
1080     return GNUNET_SYSERR;
1081   }
1082   return GNUNET_OK;
1083 }
1084
1085
1086 /**
1087  * Start a service at a peer using its ARM service
1088  *
1089  * @param peer the peer whose service has to be started
1090  * @param service_name name of the service to start
1091  * @param timeout how long should the ARM API try to send the request to start
1092  *          the service
1093  * @param cont the callback to call with result and status from ARM API
1094  * @param cont_cls the closure for the above callback
1095  * @return GNUNET_OK upon successfully queuing the service start request;
1096  *           GNUNET_SYSERR upon error
1097  */
1098 int
1099 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1100                                    const char *service_name,
1101                                    struct GNUNET_TIME_Relative timeout,
1102                                    GNUNET_ARM_ResultCallback cont,
1103                                    void *cont_cls)
1104 {
1105   if (NULL == peer->ah)
1106     return GNUNET_SYSERR;
1107   GNUNET_ARM_request_service_start (peer->ah,
1108                                     service_name,
1109                                     GNUNET_OS_INHERIT_STD_ALL,
1110                                     timeout,
1111                                     cont, cont_cls);
1112   return GNUNET_OK;
1113 }
1114
1115
1116 /**
1117  * Stop a service at a peer using its ARM service
1118  *
1119  * @param peer the peer whose service has to be stopped
1120  * @param service_name name of the service to stop
1121  * @param timeout how long should the ARM API try to send the request to stop
1122  *          the service
1123  * @param cont the callback to call with result and status from ARM API
1124  * @param cont_cls the closure for the above callback
1125  * @return GNUNET_OK upon successfully queuing the service stop request;
1126  *           GNUNET_SYSERR upon error
1127  */
1128 int 
1129 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1130                                   const char *service_name,
1131                                   struct GNUNET_TIME_Relative timeout,
1132                                   GNUNET_ARM_ResultCallback cont,
1133                                   void *cont_cls)
1134 {
1135   if (NULL == peer->ah)
1136     return GNUNET_SYSERR;
1137   GNUNET_ARM_request_service_stop (peer->ah, 
1138                                    service_name,
1139                                    timeout,
1140                                    cont, cont_cls);
1141   return GNUNET_OK;
1142 }
1143                                        
1144
1145 /**
1146  * Sends SIGTERM to the peer's main process
1147  *
1148  * @param peer the handle to the peer
1149  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1150  *           or upon any error while sending SIGTERM
1151  */
1152 int
1153 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1154 {
1155   if (NULL == peer->main_process)
1156   {
1157     GNUNET_break (0);
1158     return GNUNET_SYSERR;
1159   }
1160   return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1161       GNUNET_OK : GNUNET_SYSERR;
1162 }
1163
1164
1165 /**
1166  * Waits for a peer to terminate. The peer's main process will also be destroyed.
1167  *
1168  * @param peer the handle to the peer
1169  * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1170  *           or upon any error while waiting
1171  */
1172 int
1173 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1174 {
1175   int ret;
1176
1177   if (NULL == peer->main_process)
1178   {
1179     GNUNET_break (0);
1180     return GNUNET_SYSERR;
1181   }
1182   ret = GNUNET_OS_process_wait (peer->main_process);
1183   GNUNET_OS_process_destroy (peer->main_process);
1184   peer->main_process = NULL;
1185   return ret;
1186 }
1187
1188
1189 /**
1190  * Stop the peer. 
1191  *
1192  * @param peer peer to stop
1193  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1194  */
1195 int
1196 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1197 {
1198   if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1199     return GNUNET_SYSERR;
1200   if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1201     return GNUNET_SYSERR;
1202   return GNUNET_OK;
1203 }
1204
1205
1206 /**
1207  * Function called whenever we connect to or disconnect from ARM.
1208  *
1209  * @param cls closure
1210  * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1211  *                  GNUNET_SYSERR on error.
1212  */
1213 static void
1214 disconn_status (void *cls, 
1215                 int connected)
1216 {
1217   struct GNUNET_TESTING_Peer *peer = cls;
1218
1219   if (GNUNET_SYSERR == connected)
1220   {
1221     peer->cb (peer->cb_cls, peer, connected);
1222     return;
1223   }
1224   if (GNUNET_YES == connected)
1225   {
1226     GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1227     return;
1228   }
1229   GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1230   GNUNET_ARM_disconnect_and_free (peer->ah);
1231   peer->ah = NULL;
1232   peer->cb (peer->cb_cls, peer, GNUNET_YES);
1233 }
1234
1235
1236 /**
1237  * Stop a peer asynchronously using ARM API.  Peer's shutdown is signaled
1238  * through the GNUNET_TESTING_PeerStopCallback().
1239  *
1240  * @param peer the peer to stop
1241  * @param cb the callback to signal peer shutdown
1242  * @param cb_cls closure for the above callback
1243  * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1244  *           does not mean that the peer is successfully stopped); GNUNET_SYSERR
1245  *           upon any error.
1246  */
1247 int
1248 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1249                                 GNUNET_TESTING_PeerStopCallback cb,
1250                                 void *cb_cls)
1251 {
1252   if (NULL == peer->main_process)
1253     return GNUNET_SYSERR;  
1254   peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1255   if (NULL == peer->ah)
1256     return GNUNET_SYSERR;
1257   peer->cb = cb;
1258   peer->cb_cls = cb_cls;
1259   return GNUNET_OK;
1260 }
1261
1262
1263 /**
1264  * Destroy the peer.  Releases resources locked during peer configuration.
1265  * If the peer is still running, it will be stopped AND a warning will be
1266  * printed (users of the API should stop the peer explicitly first).
1267  *
1268  * @param peer peer to destroy
1269  */
1270 void
1271 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1272 {
1273   unsigned int cnt;
1274
1275   if (NULL != peer->main_process)
1276     GNUNET_TESTING_peer_stop (peer);
1277   if (NULL != peer->ah)
1278     GNUNET_ARM_disconnect_and_free (peer->ah);
1279   if (NULL != peer->mh)
1280     GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1281   GNUNET_free (peer->cfgfile);
1282   if (NULL != peer->cfg)
1283     GNUNET_CONFIGURATION_destroy (peer->cfg);
1284   GNUNET_free (peer->main_binary);
1285   GNUNET_free (peer->args);
1286   GNUNET_free_non_null (peer->id);
1287   if (NULL != peer->ports)
1288   {
1289     for (cnt = 0; cnt < peer->nports; cnt++)
1290       GNUNET_TESTING_release_port (peer->system, 
1291                                    GNUNET_YES,
1292                                    peer->ports[cnt]);
1293     GNUNET_free (peer->ports);
1294   }
1295   GNUNET_free (peer);
1296 }
1297
1298
1299 /**
1300  * Start a single peer and run a test using the testing library.
1301  * Starts a peer using the given configuration and then invokes the
1302  * given callback.  This function ALSO initializes the scheduler loop
1303  * and should thus be called directly from "main".  The testcase
1304  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1305  *
1306  * @param testdir only the directory name without any path. This is used for
1307  *          all service homes; the directory will be created in a temporary
1308  *          location depending on the underlying OS
1309  * @param cfgfilename name of the configuration file to use;
1310  *         use NULL to only run with defaults
1311  * @param tm main function of the testcase
1312  * @param tm_cls closure for 'tm'
1313  * @return 0 on success, 1 on error
1314  */
1315 int
1316 GNUNET_TESTING_peer_run (const char *testdir,
1317                          const char *cfgfilename,
1318                          GNUNET_TESTING_TestMain tm,
1319                          void *tm_cls)
1320 {
1321   return GNUNET_TESTING_service_run (testdir, "arm",
1322                                      cfgfilename, tm, tm_cls);
1323 }
1324
1325
1326 /**
1327  * Structure for holding service data
1328  */
1329 struct ServiceContext
1330 {
1331   /**
1332    * The configuration of the peer in which the service is run
1333    */
1334   const struct GNUNET_CONFIGURATION_Handle *cfg;
1335
1336   /**
1337    * Callback to signal service startup
1338    */
1339   GNUNET_TESTING_TestMain tm;
1340   
1341   /**
1342    * The peer in which the service is run.
1343    */
1344   struct GNUNET_TESTING_Peer *peer;
1345
1346   /**
1347    * Closure for the above callback
1348    */
1349   void *tm_cls;
1350 };
1351
1352
1353 /**
1354  * Callback to be called when SCHEDULER has been started
1355  *
1356  * @param cls the ServiceContext
1357  * @param tc the TaskContext
1358  */
1359 static void
1360 service_run_main (void *cls,
1361                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1362 {
1363   struct ServiceContext *sc = cls;
1364
1365   sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1366 }
1367
1368
1369 /**
1370  * Start a single service (no ARM, except of course if the given
1371  * service name is 'arm') and run a test using the testing library.
1372  * Starts a service using the given configuration and then invokes the
1373  * given callback.  This function ALSO initializes the scheduler loop
1374  * and should thus be called directly from "main".  The testcase
1375  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1376  *
1377  * This function is useful if the testcase is for a single service
1378  * and if that service doesn't itself depend on other services.
1379  *
1380  * @param testdir only the directory name without any path. This is used for
1381  *          all service homes; the directory will be created in a temporary
1382  *          location depending on the underlying OS
1383  * @param service_name name of the service to run
1384  * @param cfgfilename name of the configuration file to use;
1385  *         use NULL to only run with defaults
1386  * @param tm main function of the testcase
1387  * @param tm_cls closure for 'tm'
1388  * @return 0 on success, 1 on error
1389  */
1390 int
1391 GNUNET_TESTING_service_run (const char *testdir,
1392                             const char *service_name,
1393                             const char *cfgfilename,
1394                             GNUNET_TESTING_TestMain tm,
1395                             void *tm_cls)
1396 {
1397   struct ServiceContext sc;
1398   struct GNUNET_TESTING_System *system;
1399   struct GNUNET_TESTING_Peer *peer;
1400   struct GNUNET_CONFIGURATION_Handle *cfg;
1401   char *binary;
1402   char *libexec_binary;
1403
1404   GNUNET_log_setup (testdir, "WARNING", NULL);
1405   system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1406   if (NULL == system)
1407     return 1;
1408   cfg = GNUNET_CONFIGURATION_create ();
1409   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1410   {
1411     LOG (GNUNET_ERROR_TYPE_ERROR,
1412          _("Failed to load configuration from %s\n"), cfgfilename);
1413     GNUNET_CONFIGURATION_destroy (cfg);
1414     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1415     return 1;
1416   }
1417   peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1418   if (NULL == peer)
1419   {
1420     GNUNET_CONFIGURATION_destroy (cfg);
1421     hostkeys_unload (system);
1422     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1423     return 1;
1424   }
1425   GNUNET_free (peer->main_binary);
1426   GNUNET_free (peer->args);
1427   GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1428   libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1429   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1430   {
1431     /* No prefix */
1432     GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1433     peer->args = strdup ("");
1434   }
1435   else
1436     peer->args = strdup (libexec_binary);
1437
1438   GNUNET_free (libexec_binary);
1439   GNUNET_free (binary);
1440   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1441   {    
1442     GNUNET_TESTING_peer_destroy (peer);
1443     GNUNET_CONFIGURATION_destroy (cfg);
1444     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1445     return 1;
1446   }
1447   sc.cfg = cfg;
1448   sc.tm = tm;
1449   sc.tm_cls = tm_cls;
1450   sc.peer = peer;
1451   GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1452   if ((NULL != peer->main_process) &&
1453       (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1454   {
1455     GNUNET_TESTING_peer_destroy (peer);
1456     GNUNET_CONFIGURATION_destroy (cfg);
1457     GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1458     return 1;
1459   }
1460   GNUNET_TESTING_peer_destroy (peer);
1461   GNUNET_CONFIGURATION_destroy (cfg);
1462   GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1463   return 0;
1464 }
1465
1466
1467 /**
1468  * Sometimes we use the binary name to determine which specific
1469  * test to run.  In those cases, the string after the last "_"
1470  * in 'argv[0]' specifies a string that determines the configuration
1471  * file or plugin to use.  
1472  *
1473  * This function returns the respective substring, taking care
1474  * of issues such as binaries ending in '.exe' on W32.
1475  *
1476  * @param argv0 the name of the binary
1477  * @return string between the last '_' and the '.exe' (or the end of the string),
1478  *         NULL if argv0 has no '_' 
1479  */
1480 char *
1481 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1482 {
1483   size_t slen = strlen (argv0) + 1;
1484   char sbuf[slen];
1485   char *ret;
1486   char *dot;
1487
1488   memcpy (sbuf, argv0, slen);
1489   ret = strrchr (sbuf, '_');
1490   if (NULL == ret)
1491     return NULL;
1492   ret++; /* skip underscore */
1493   dot = strchr (ret, '.');
1494   if (NULL != dot)
1495     *dot = '\0';
1496   return GNUNET_strdup (ret);
1497 }
1498
1499
1500 /* end of testing.c */