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