-GNUNET_TESTING_peer_configure
[oweals/gnunet.git] / src / testing / testing_new.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_new.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_testing_lib-new.h"
35
36 #define LOG(kind,...)                                           \
37   GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__)
38
39 /**
40  * AI_NUMERICSERV not defined in windows. A hack to keep on going.
41  */
42 #if !defined (AI_NUMERICSERV)
43 #define AI_NUMERICSERV 0
44 #endif
45
46 /**
47  * Size of a hostkey when written to a file
48  */
49 #ifndef HOSTKEYFILESIZE
50 #define HOSTKEYFILESIZE 914
51 #endif
52
53 /**
54  * Handle for a system on which GNUnet peers are executed;
55  * a system is used for reserving unique paths and ports.
56  */
57 struct GNUNET_TESTING_System
58 {
59   /**
60    * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
61    * SERVICEHOME. 
62    */
63   char *tmppath;
64
65   /**
66    * The hostname of the controller
67    */
68   char *controller;
69
70   /**
71    * Hostkeys data
72    */
73   char *hostkeys_data;
74
75   /**
76    * Bitmap where each TCP port that has already been reserved for
77    * some GNUnet peer is recorded.  Note that we additionally need to
78    * test if a port is already in use by non-GNUnet components before
79    * assigning it to a peer/service.  If we detect that a port is
80    * already in use, we also mark it in this bitmap.  So all the bits
81    * that are zero merely indicate ports that MIGHT be available for
82    * peers.
83    */
84   uint32_t reserved_tcp_ports[65536 / 32];
85
86   /**
87    * Bitmap where each UDP port that has already been reserved for
88    * some GNUnet peer is recorded.  Note that we additionally need to
89    * test if a port is already in use by non-GNUnet components before
90    * assigning it to a peer/service.  If we detect that a port is
91    * already in use, we also mark it in this bitmap.  So all the bits
92    * that are zero merely indicate ports that MIGHT be available for
93    * peers.
94    */
95   uint32_t reserved_udp_ports[65536 / 32];
96
97   /**
98    * Counter we use to make service home paths unique on this system;
99    * the full path consists of the tmppath and this number.  Each
100    * UNIXPATH for a peer is also modified to include the respective
101    * path counter to ensure uniqueness.  This field is incremented
102    * by one for each configured peer.  Even if peers are destroyed,
103    * we never re-use path counters.
104    */
105   uint32_t path_counter;  
106
107   /**
108    * The number of hostkeys
109    */
110   uint32_t total_hostkeys;
111 };
112
113
114 /**
115  * Handle for a GNUnet peer controlled by testing.
116  */
117 struct GNUNET_TESTING_Peer
118 {
119
120   /**
121    * Path to the configuration file for this peer.
122    */
123   char *cfgfile;
124
125   /**
126    * Binary to be executed during 'GNUNET_TESTING_peer_start'.
127    * Typically 'gnunet-service-arm' (but can be set to a 
128    * specific service by 'GNUNET_TESTING_service_run' if
129    * necessary).
130    */ 
131   char *main_binary;
132   
133   /**
134    * Handle to the running binary of the service, NULL if the
135    * peer/service is currently not running.
136    */
137   struct GNUNET_OS_Process *main_process;
138 };
139
140
141 /**
142  * Lowest port used for GNUnet testing.  Should be high enough to not
143  * conflict with other applications running on the hosts but be low
144  * enough to not conflict with client-ports (typically starting around
145  * 32k).
146  */
147 #define LOW_PORT 12000
148
149
150 /**
151  * Highest port used for GNUnet testing.  Should be low enough to not
152  * conflict with the port range for "local" ports (client apps; see
153  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
154  */
155 #define HIGH_PORT 56000
156
157
158 /**
159  * Create a system handle.  There must only be one system
160  * handle per operating system.
161  *
162  * @param tmppath prefix path to use for all service homes
163  * @param controller hostname of the controlling host, 
164  *        service configurations are modified to allow 
165  *        control connections from this host; can be NULL
166  * @return handle to this system, NULL on error
167  */
168 struct GNUNET_TESTING_System *
169 GNUNET_TESTING_system_create (const char *tmppath,
170                               const char *controller)
171 {
172   struct GNUNET_TESTING_System *system;
173
174   if (NULL == tmppath)
175     return NULL;
176   system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
177   system->tmppath = GNUNET_strdup (tmppath);
178   if (NULL != controller)
179     system->controller = GNUNET_strdup (controller);
180   return system;
181 }
182
183
184 /**
185  * Free system resources.
186  *
187  * @param system system to be freed
188  * @param remove_paths should the 'tmppath' and all subdirectories
189  *        be removed (clean up on shutdown)?
190  */
191 void
192 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
193                                int remove_paths)
194 {
195   GNUNET_assert (NULL != system);
196   if (NULL != system->hostkeys_data)
197   {
198     GNUNET_break (0);           /* Use GNUNET_TESTING_hostkeys_unload() */
199     GNUNET_free (system->hostkeys_data);
200     system->hostkeys_data = NULL;
201     system->total_hostkeys = 0;
202   }
203   if (GNUNET_YES == remove_paths)
204     GNUNET_DISK_directory_remove (system->tmppath);
205   GNUNET_free (system->tmppath);
206   GNUNET_free_non_null (system->controller);
207   GNUNET_free (system);
208 }
209
210
211 /**
212  * Reserve a TCP or UDP port for a peer.
213  *
214  * @param system system to use for reservation tracking
215  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
216  * @return 0 if no free port was available
217  */
218 uint16_t 
219 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
220                              int is_tcp)
221 {
222   struct GNUNET_NETWORK_Handle *socket;
223   struct addrinfo hint;
224   struct addrinfo *ret;
225   uint32_t *port_buckets;
226   char *open_port_str;
227   int bind_status;
228   uint32_t xor_image;
229   uint16_t index;
230   uint16_t open_port;
231   uint16_t pos;
232
233   hint.ai_family = AF_UNSPEC;   /* IPv4 and IPv6 */
234   hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
235   hint.ai_protocol = 0;
236   hint.ai_addrlen = 0;
237   hint.ai_addr = NULL;
238   hint.ai_canonname = NULL;
239   hint.ai_next = NULL;
240   hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;  /* Wild card address */
241   port_buckets = (GNUNET_YES == is_tcp) ?
242     system->reserved_tcp_ports : system->reserved_udp_ports;
243   for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
244   {
245     xor_image = (UINT32_MAX ^ port_buckets[index]);
246     if (0 == xor_image)        /* Ports in the bucket are full */
247       continue;
248     pos = 0;
249     while (pos < 32)
250     {
251       if (0 == ((xor_image >> pos) & 1U))
252       {
253         pos++;
254         continue;
255       }
256       open_port = (index * 32) + pos;
257       GNUNET_asprintf (&open_port_str, "%u", open_port);
258       ret = NULL;
259       GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
260       GNUNET_free (open_port_str);  
261       socket = GNUNET_NETWORK_socket_create (ret->ai_family,
262                                              (GNUNET_YES == is_tcp) ?
263                                              SOCK_STREAM : SOCK_DGRAM,
264                                              0);
265       GNUNET_assert (NULL != socket);
266       bind_status = GNUNET_NETWORK_socket_bind (socket,
267                                                 ret->ai_addr,
268                                                 ret->ai_addrlen);
269       freeaddrinfo (ret);
270       GNUNET_NETWORK_socket_close (socket);
271       socket = NULL;
272       port_buckets[index] |= (1U << pos); /* Set the port bit */
273       if (GNUNET_OK == bind_status)
274         return open_port;
275       pos++;
276     }
277   }
278   return 0;
279 }
280
281
282 /**
283  * Release reservation of a TCP or UDP port for a peer
284  * (used during GNUNET_TESTING_peer_destroy).
285  *
286  * @param system system to use for reservation tracking
287  * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
288  * @param port reserved port to release
289  */
290 void
291 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
292                              int is_tcp,
293                              uint16_t port)
294 {
295   uint32_t *port_buckets;
296   uint16_t bucket;
297   uint16_t pos;
298
299   GNUNET_assert (NULL != system);
300   port_buckets = (GNUNET_YES == is_tcp) ?
301     system->reserved_tcp_ports : system->reserved_udp_ports;
302   bucket = port / 32;
303   pos = port % 32;
304   LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
305   if (0 == (port_buckets[bucket] & (1U << pos)))
306   {
307     GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
308     return;
309   }
310   port_buckets[bucket] &= ~(1U << pos);
311 }
312
313
314 /**
315  * Reserve a SERVICEHOME path for a peer.
316  *
317  * @param system system to use for reservation tracking
318  * @return NULL on error, otherwise fresh unique path to use
319  *         as the servicehome for the peer; must be freed by the caller
320  */
321 // static 
322 char *
323 reserve_path (struct GNUNET_TESTING_System *system)
324 {
325   char *reserved_path;
326
327   GNUNET_asprintf (&reserved_path,
328                    "%s/%u", system->tmppath, system->path_counter++);
329   return reserved_path;
330 }             
331
332
333 /**
334  * Testing includes a number of pre-created hostkeys for faster peer
335  * startup. This function loads such keys into memory from a file.
336  *
337  * @param system the testing system handle
338  * @param filename the path of the hostkeys file
339  * @return GNUNET_OK on success; GNUNET_SYSERR on error
340  */
341 int
342 GNUNET_TESTING_hostkeys_load (struct GNUNET_TESTING_System *system,
343                               const char *filename)
344 {
345  struct GNUNET_DISK_FileHandle *fd;
346  uint64_t fs;
347  
348  if (GNUNET_YES != GNUNET_DISK_file_test (filename))
349   {
350     LOG (GNUNET_ERROR_TYPE_ERROR,
351          "Hostkeys file not found: %s\n", filename);
352     return GNUNET_SYSERR;
353   }
354   /* Check hostkey file size, read entire thing into memory */
355   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
356                               GNUNET_DISK_PERM_NONE);
357   if (NULL == fd)
358   {
359     LOG (GNUNET_ERROR_TYPE_ERROR,
360          "Could not open hostkeys file: %s\n", filename);
361     return GNUNET_SYSERR;
362   }
363   if (GNUNET_OK != 
364       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
365     fs = 0;
366   if (0 == fs)
367   {
368     GNUNET_DISK_file_close (fd);
369     return GNUNET_SYSERR;       /* File is empty */
370   }
371   if (0 != (fs % HOSTKEYFILESIZE))
372   {
373     GNUNET_DISK_file_close (fd);
374     LOG (GNUNET_ERROR_TYPE_ERROR,
375          "Incorrect hostkey file format: %s\n", filename);
376     return GNUNET_SYSERR;
377   }
378   GNUNET_break (NULL == system->hostkeys_data);
379   system->total_hostkeys = fs / HOSTKEYFILESIZE;
380   system->hostkeys_data = GNUNET_malloc_large (fs); /* free in hostkeys_unload */
381   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, system->hostkeys_data, fs));
382   GNUNET_DISK_file_close (fd);
383   return GNUNET_OK;
384 }
385
386
387 /**
388  * Function to remove the loaded hostkeys
389  *
390  * @param system the testing system handle
391  */
392 void
393 GNUNET_TESTING_hostkeys_unload (struct GNUNET_TESTING_System *system)
394 {
395   GNUNET_break (NULL != system->hostkeys_data);
396   GNUNET_free_non_null (system->hostkeys_data);
397   system->hostkeys_data = NULL;
398   system->total_hostkeys = 0;
399 }
400
401
402 /**
403  * Testing includes a number of pre-created hostkeys for
404  * faster peer startup.  This function can be used to
405  * access the n-th key of those pre-created hostkeys; note
406  * that these keys are ONLY useful for testing and not
407  * secure as the private keys are part of the public 
408  * GNUnet source code.
409  *
410  * This is primarily a helper function used internally
411  * by 'GNUNET_TESTING_peer_configure'.
412  *
413  * @param system the testing system handle
414  * @param key_number desired pre-created hostkey to obtain
415  * @param id set to the peer's identity (hash of the public
416  *        key; if NULL, GNUNET_SYSERR is returned immediately
417  * @return GNUNET_SYSERR on error (not enough keys)
418  */
419 int
420 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
421                             uint32_t key_number,
422                             struct GNUNET_PeerIdentity *id)
423 {  
424   struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
425   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
426   
427   if ((NULL == id) || (NULL == system->hostkeys_data))
428     return GNUNET_SYSERR;
429   if (key_number >= system->total_hostkeys)
430   {
431     LOG (GNUNET_ERROR_TYPE_DEBUG,
432          "Key number %u doesn't exist\n", key_number);
433     return GNUNET_SYSERR;
434   }   
435   private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
436                                               (key_number * HOSTKEYFILESIZE),
437                                               HOSTKEYFILESIZE);
438   if (NULL == private_key)
439   {
440     LOG (GNUNET_ERROR_TYPE_DEBUG,
441          "Error while decoding key %u\n", key_number);
442     return GNUNET_SYSERR;
443   }
444   GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
445   GNUNET_CRYPTO_hash (&public_key,
446                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
447                       &(id->hashPubKey));
448   GNUNET_CRYPTO_rsa_key_free (private_key);
449   return GNUNET_OK;
450 }
451
452
453 /**
454  * Structure for holding data to build new configurations from a configuration
455  * template
456  */
457 struct UpdateContext
458 {
459   /**
460    * The system for which we are building configurations
461    */
462   struct GNUNET_TESTING_System *system;
463   
464   /**
465    * The configuration we are building
466    */
467   struct GNUNET_CONFIGURATION_Handle *cfg;
468
469   /**
470    * The customized service home path for this peer
471    */
472   char *service_home;
473
474   /**
475    * build status - to signal error while building a configuration
476    */
477   int status;
478 };
479
480
481 /**
482  * Function to iterate over options.  Copies
483  * the options to the target configuration,
484  * updating PORT values as needed.
485  *
486  * @param cls the UpdateContext
487  * @param section name of the section
488  * @param option name of the option
489  * @param value value of the option
490  */
491 static void
492 update_config (void *cls, const char *section, const char *option,
493                const char *value)
494 {
495   struct UpdateContext *uc = cls;
496   unsigned int ival;
497   char cval[12];
498   char uval[128];
499   char *single_variable;
500   char *per_host_variable;
501   unsigned long long num_per_host;
502   uint16_t new_port;
503
504   if (GNUNET_OK != uc->status)
505     return;
506   GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
507   GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
508   if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
509   {
510     if ((ival != 0) &&
511         (GNUNET_YES !=
512          GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
513                                                single_variable)))
514     {
515       /* FIXME: What about UDP? */
516       new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
517       if (0 == new_port)
518       {
519         uc->status = GNUNET_SYSERR;
520         return;
521       }
522       GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
523       value = cval;
524     }
525     else if ((ival != 0) &&
526              (GNUNET_YES ==
527               GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
528                                                     single_variable)) &&
529              GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
530                                                     per_host_variable,
531                                                     &num_per_host))
532     {
533       /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
534       /*                  ival + ctx->fdnum % num_per_host); */
535       /* value = cval; */
536       GNUNET_break (0);         /* FIXME */
537     }
538   }
539   if (0 == strcmp (option, "UNIXPATH"))
540   {
541     if (GNUNET_YES !=
542         GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
543                                               single_variable))
544     {
545       GNUNET_snprintf (uval, sizeof (uval), "%s\\%s.sock",
546                        uc->service_home, section);
547       value = uval;
548     }
549     else if ((GNUNET_YES ==
550               GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
551                                                      per_host_variable,
552                                                      &num_per_host)) &&
553              (num_per_host > 0))
554     {
555       GNUNET_break(0);          /* FIXME */
556     }
557   }
558   if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
559   {
560     value = uc->system->controller;
561   }
562   GNUNET_free (single_variable);
563   GNUNET_free (per_host_variable);
564   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
565 }
566
567
568 /**
569  * Section iterator to set ACCEPT_FROM in all sections
570  *
571  * @param cls the UpdateContext
572  * @param section name of the section
573  */
574 static void
575 update_config_sections (void *cls,
576                         const char *section)
577 {
578   struct UpdateContext *uc = cls;
579   char *orig_allowed_hosts;
580   char *allowed_hosts;
581
582   if (GNUNET_OK != 
583       GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
584                                              &orig_allowed_hosts))
585   {
586     orig_allowed_hosts = "127.0.0.1;";
587   }
588   if (NULL == uc->system->controller)
589     allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
590   else
591     GNUNET_asprintf (&allowed_hosts, "%s %s;", orig_allowed_hosts,
592                      uc->system->controller);
593   GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
594                                          allowed_hosts);
595   GNUNET_free (allowed_hosts);  
596 }
597
598
599 /**
600  * Create a new configuration using the given configuration
601  * as a template; ports and paths will be modified to select
602  * available ports on the local system.  If we run
603  * out of "*port" numbers, return SYSERR.
604  *
605  * This is primarily a helper function used internally
606  * by 'GNUNET_TESTING_peer_configure'.
607  *
608  * @param system system to use to coordinate resource usage
609  * @param cfg template configuration to update
610  * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
611  *           be incomplete and should not be used there upon
612  */
613 int
614 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
615                                      struct GNUNET_CONFIGURATION_Handle *cfg)
616 {
617   struct UpdateContext uc;
618   
619   uc.system = system;
620   uc.cfg = cfg;
621   uc.status = GNUNET_OK;
622   GNUNET_asprintf (&uc.service_home, "%s\\%u", system->tmppath,
623                    system->path_counter++);
624   GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
625                                          uc.service_home);
626   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
627   GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
628   /* FIXME: add other options which enable communication with controller */
629   GNUNET_free (uc.service_home);
630   return uc.status;
631 }
632
633
634 /**
635  * Configure a GNUnet peer.  GNUnet must be installed on the local
636  * system and available in the PATH. 
637  *
638  * @param system system to use to coordinate resource usage
639  * @param cfg configuration to use; will be UPDATED (to reflect needed
640  *            changes in port numbers and paths)
641  * @param key_number number of the hostkey to use for the peer
642  * @param id identifier for the daemon, will be set, can be NULL
643  * @param emsg set to error message (set to NULL on success), can be NULL
644  * @return handle to the peer, NULL on error
645  */
646 struct GNUNET_TESTING_Peer *
647 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
648                                struct GNUNET_CONFIGURATION_Handle *cfg,
649                                uint32_t key_number,
650                                struct GNUNET_PeerIdentity *id,
651                                char **emsg)
652 {
653   struct GNUNET_TESTING_Peer *peer;
654   struct GNUNET_DISK_FileHandle *fd;
655   char *service_home;  
656   char hostkey_filename[128];
657   char *config_filename;
658   size_t bytes_written;
659   size_t n;
660
661
662   if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
663     return NULL;
664   if (key_number >= system->total_hostkeys)
665     return NULL;
666   if ((NULL != id) &&
667       (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id)))
668     return NULL;
669   GNUNET_assert (GNUNET_OK == 
670                  GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
671                                                         "SERVICE_HOME",
672                                                         &service_home));
673   GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s\\.hostkey",
674                    service_home);
675   fd = GNUNET_DISK_file_open (hostkey_filename,
676                               GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
677                               GNUNET_DISK_PERM_USER_READ 
678                               | GNUNET_DISK_PERM_USER_WRITE);
679   if (NULL == fd)
680   {
681     GNUNET_break (0); return NULL;
682   }
683   bytes_written = 0;
684   do
685   {
686     n = GNUNET_DISK_file_write (fd, system->hostkeys_data 
687                                 + (key_number * HOSTKEYFILESIZE),
688                                 HOSTKEYFILESIZE - bytes_written);
689     GNUNET_assert (GNUNET_SYSERR != n);
690     bytes_written += n;
691   }
692   while (bytes_written < HOSTKEYFILESIZE);
693   GNUNET_DISK_file_close (fd);
694   fd = NULL;  
695   GNUNET_asprintf (&config_filename, "%s\\config", service_home);
696   GNUNET_free (service_home);
697   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
698       return NULL;
699   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
700   peer->cfgfile = config_filename; /* Free in peer_destroy */
701   peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
702   return peer;
703 }
704
705
706 /**
707  * Start the peer. 
708  *
709  * @param peer peer to start
710  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
711  */
712 int
713 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
714 {
715   GNUNET_break (0);
716   return GNUNET_SYSERR;
717 }
718
719
720 /**
721  * Stop the peer. 
722  *
723  * @param peer peer to stop
724  * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
725  */
726 int
727 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
728 {
729   GNUNET_break (0);
730   return GNUNET_SYSERR;
731 }
732
733
734 /**
735  * Destroy the peer.  Releases resources locked during peer configuration.
736  * If the peer is still running, it will be stopped AND a warning will be
737  * printed (users of the API should stop the peer explicitly first).
738  *
739  * @param peer peer to destroy
740  */
741 void
742 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
743 {
744   GNUNET_break (0);
745 }
746
747
748
749 /**
750  * Start a single peer and run a test using the testing library.
751  * Starts a peer using the given configuration and then invokes the
752  * given callback.  This function ALSO initializes the scheduler loop
753  * and should thus be called directly from "main".  The testcase
754  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
755  *
756  * @param tmppath path for storing temporary data for the test
757  * @param cfgfilename name of the configuration file to use;
758  *         use NULL to only run with defaults
759  * @param tm main function of the testcase
760  * @param tm_cls closure for 'tm'
761  * @return 0 on success, 1 on error
762  */
763 int
764 GNUNET_TESTING_peer_run (const char *tmppath,
765                          const char *cfgfilename,
766                          GNUNET_TESTING_TestMain tm,
767                          void *tm_cls)
768 {
769   return GNUNET_TESTING_service_run (tmppath, "arm",
770                                      cfgfilename, tm, tm_cls);
771 }
772
773
774
775 /**
776  * Start a single service (no ARM, except of course if the given
777  * service name is 'arm') and run a test using the testing library.
778  * Starts a service using the given configuration and then invokes the
779  * given callback.  This function ALSO initializes the scheduler loop
780  * and should thus be called directly from "main".  The testcase
781  * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
782  *
783  * This function is useful if the testcase is for a single service
784  * and if that service doesn't itself depend on other services.
785  *
786  * @param tmppath path for storing temporary data for the test
787  * @param service_name name of the service to run
788  * @param cfgfilename name of the configuration file to use;
789  *         use NULL to only run with defaults
790  * @param tm main function of the testcase
791  * @param tm_cls closure for 'tm'
792  * @return 0 on success, 1 on error
793  */
794 int
795 GNUNET_TESTING_service_run (const char *tmppath,
796                             const char *service_name,
797                             const char *cfgfilename,
798                             GNUNET_TESTING_TestMain tm,
799                             void *tm_cls)
800 {
801   GNUNET_break (0);
802   return 1;
803 }
804
805
806
807 /* end of testing_new.c */