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