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