misc train hacking
[oweals/gnunet.git] / src / testing / testing.c
1 /*
2       This file is part of GNUnet
3       (C) 2008, 2009 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 gnunetd,
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!
29  * @author Christian Grothoff
30  *
31  */
32 #include "platform.h"
33 #include "gnunet_arm_service.h"
34 #include "gnunet_core_service.h"
35 #include "gnunet_constants.h"
36 #include "gnunet_testing_lib.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_hello_lib.h"
39
40 #define DEBUG_TESTING GNUNET_NO
41
42 #define DEBUG_TESTING_RECONNECT GNUNET_NO
43
44 /**
45  * Hack to deal with initial HELLO's being often devoid of addresses.
46  * This hack causes 'process_hello' to ignore HELLOs without addresses.
47  * The correct implementation would continue with 'process_hello' until
48  * the connection could be established...
49  */
50 #define EMPTY_HACK GNUNET_YES
51
52 /**
53  * How long do we wait after starting gnunet-service-arm
54  * for the core service to be alive?
55  */
56 #define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
57
58 /**
59  * How many times are we willing to try to wait for "scp" or
60  * "gnunet-service-arm" to complete (waitpid) before giving up?
61  */
62 #define MAX_EXEC_WAIT_RUNS 250
63
64 static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} };
65
66 #if EMPTY_HACK
67 static int
68 test_address (void *cls, const char *tname,
69               struct GNUNET_TIME_Absolute expiration, const void *addr,
70               uint16_t addrlen)
71 {
72   int *empty = cls;
73
74   *empty = GNUNET_NO;
75   return GNUNET_OK;
76 }
77 #endif
78
79 /**
80  * Receive the HELLO from one peer, give it to the other
81  * and ask them to connect.
82  *
83  * @param cls "struct ConnectContext"
84  * @param message HELLO message of peer
85  */
86 static void
87 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
88 {
89   struct GNUNET_TESTING_Daemon *daemon = cls;
90   int msize;
91 #if EMPTY_HACK
92   int empty;
93
94   empty = GNUNET_YES;
95   GNUNET_assert (message != NULL);
96   GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message,
97                                   GNUNET_NO, &test_address, &empty);
98   if (GNUNET_YES == empty)
99   {
100 #if DEBUG_TESTING
101     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping empty HELLO address\n");
102 #endif
103     return;
104   }
105 #endif
106   GNUNET_assert (daemon->phase == SP_GET_HELLO ||
107                  daemon->phase == SP_START_DONE);
108   daemon->cb = NULL;
109   if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */
110     GNUNET_SCHEDULER_cancel (daemon->task);
111
112   if (daemon->server != NULL)
113   {
114 #if DEBUG_TESTING
115     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116                 "Received `%s' from transport service of `%4s', disconnecting core!\n",
117                 "HELLO", GNUNET_i2s (&daemon->id));
118 #endif
119     GNUNET_CORE_disconnect (daemon->server);
120     daemon->server = NULL;
121   }
122
123   msize = ntohs (message->size);
124   if (msize < 1)
125   {
126     return;
127   }
128   if (daemon->ghh != NULL)
129   {
130     GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh);
131   }
132 #if DEBUG_TESTING
133   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
134               "Received `%s' from transport service of `%4s'\n", "HELLO",
135               GNUNET_i2s (&daemon->id));
136 #endif
137
138   GNUNET_free_non_null (daemon->hello);
139   daemon->hello = GNUNET_malloc (msize);
140   memcpy (daemon->hello, message, msize);
141
142   if (daemon->th != NULL)
143   {
144     GNUNET_TRANSPORT_disconnect (daemon->th);
145     daemon->th = NULL;
146   }
147   daemon->phase = SP_START_DONE;
148 }
149
150 static void
151 start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
152
153 /**
154  * Notify of a peer being up and running.  Scheduled as a task
155  * so that variables which may need to be set are set before
156  * the connect callback can set up new operations.
157  *
158  * @param cls the testing daemon
159  * @param tc task scheduler context
160  */
161 static void
162 notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
163 {
164   struct GNUNET_TESTING_Daemon *d = cls;
165   GNUNET_TESTING_NotifyDaemonRunning cb;
166
167   cb = d->cb;
168   d->cb = NULL;
169   if (NULL != cb)
170     cb (d->cb_cls, &d->id, d->cfg, d, NULL);
171 }
172
173
174 /**
175  * Finite-state machine for starting GNUnet.
176  *
177  * @param cls our "struct GNUNET_TESTING_Daemon"
178  * @param tc unused
179  */
180 static void
181 start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
182 {
183   struct GNUNET_TESTING_Daemon *d = cls;
184   GNUNET_TESTING_NotifyDaemonRunning cb;
185   enum GNUNET_OS_ProcessStatusType type;
186   unsigned long code;
187   char *dst;
188   int bytes_read;
189
190 #if DEBUG_TESTING
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer FSM is in phase %u.\n", d->phase);
192 #endif
193
194   d->task = GNUNET_SCHEDULER_NO_TASK;
195   switch (d->phase)
196   {
197   case SP_COPYING:
198     /* confirm copying complete */
199     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
200     {
201       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
202       {
203         cb = d->cb;
204         d->cb = NULL;
205         if (NULL != cb)
206           cb (d->cb_cls, NULL, d->cfg, d,
207               _
208               ("`scp' does not seem to terminate (timeout copying config).\n"));
209         return;
210       }
211       /* wait some more */
212       d->task =
213           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
214                                         d);
215       return;
216     }
217     if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
218     {
219       cb = d->cb;
220       d->cb = NULL;
221       if (NULL != cb)
222         cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n"));
223       return;
224     }
225     GNUNET_OS_process_close (d->proc);
226 #if DEBUG_TESTING
227     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228                 "Successfully copied configuration file.\n");
229 #endif
230     d->phase = SP_COPIED;
231     /* fall-through */
232   case SP_COPIED:
233     /* Start create hostkey process if we don't already know the peer identity! */
234     if (GNUNET_NO == d->have_hostkey)
235     {
236       d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES);
237       if (d->pipe_stdout == NULL)
238       {
239         cb = d->cb;
240         d->cb = NULL;
241         if (NULL != cb)
242           cb (d->cb_cls, NULL, d->cfg, d,
243               (NULL ==
244                d->hostname) ?
245               _("Failed to create pipe for `gnunet-peerinfo' process.\n") :
246               _("Failed to create pipe for `ssh' process.\n"));
247         return;
248       }
249       if (NULL == d->hostname)
250       {
251 #if DEBUG_TESTING
252         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253                     "Starting `%s', with command `%s %s %s %s'.\n",
254                     "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile,
255                     "-sq");
256 #endif
257         d->proc =
258             GNUNET_OS_start_process (NULL, d->pipe_stdout, "gnunet-peerinfo",
259                                      "gnunet-peerinfo", "-c", d->cfgfile, "-sq",
260                                      NULL);
261         GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
262       }
263       else
264       {
265         if (d->username != NULL)
266           GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname);
267         else
268           dst = GNUNET_strdup (d->hostname);
269
270 #if DEBUG_TESTING
271         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272                     "Starting `%s', with command `%s %s %s %s %s %s'.\n",
273                     "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c",
274                     d->cfgfile, "-sq");
275 #endif
276         if (d->ssh_port_str == NULL)
277         {
278           d->proc = GNUNET_OS_start_process (NULL, d->pipe_stdout, "ssh", "ssh",
279 #if !DEBUG_TESTING
280                                              "-q",
281 #endif
282                                              dst, "gnunet-peerinfo", "-c",
283                                              d->cfgfile, "-sq", NULL);
284         }
285         else
286         {
287           d->proc =
288               GNUNET_OS_start_process (NULL, d->pipe_stdout, "ssh", "ssh", "-p",
289                                        d->ssh_port_str,
290 #if !DEBUG_TESTING
291                                        "-q",
292 #endif
293                                        dst, "gnunet-peerinfo", "-c", d->cfgfile,
294                                        "-sq", NULL);
295         }
296         GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
297         GNUNET_free (dst);
298       }
299       if (NULL == d->proc)
300       {
301         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
302                     _("Could not start `%s' process to create hostkey.\n"),
303                     (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh");
304         cb = d->cb;
305         d->cb = NULL;
306         if (NULL != cb)
307           cb (d->cb_cls, NULL, d->cfg, d,
308               (NULL ==
309                d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n")
310               : _("Failed to start `ssh' process.\n"));
311         GNUNET_DISK_pipe_close (d->pipe_stdout);
312         return;
313       }
314 #if DEBUG_TESTING
315       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316                   "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo");
317 #endif
318       d->phase = SP_HOSTKEY_CREATE;
319       d->task =
320           GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
321                                           (d->max_timeout),
322                                           GNUNET_DISK_pipe_handle
323                                           (d->pipe_stdout,
324                                            GNUNET_DISK_PIPE_END_READ),
325                                           &start_fsm, d);
326     }
327     else                        /* Already have a hostkey! */
328     {
329       if (d->hostkey_callback != NULL)
330       {
331         d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL);
332         d->hostkey_callback = NULL;
333         d->phase = SP_HOSTKEY_CREATED;
334       }
335       else
336         d->phase = SP_TOPOLOGY_SETUP;
337
338       /* wait some more */
339       d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
340     }
341     break;
342   case SP_HOSTKEY_CREATE:
343     bytes_read =
344         GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle
345                                (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ),
346                                &d->hostkeybuf[d->hostkeybufpos],
347                                sizeof (d->hostkeybuf) - d->hostkeybufpos);
348     if (bytes_read > 0)
349       d->hostkeybufpos += bytes_read;
350
351     if ((d->hostkeybufpos < 104) && (bytes_read > 0))
352     {
353       /* keep reading */
354       d->task =
355           GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
356                                           (d->max_timeout),
357                                           GNUNET_DISK_pipe_handle
358                                           (d->pipe_stdout,
359                                            GNUNET_DISK_PIPE_END_READ),
360                                           &start_fsm, d);
361       return;
362     }
363     d->hostkeybuf[103] = '\0';
364
365     if ((bytes_read < 0) ||
366         (GNUNET_OK !=
367          GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey)))
368     {
369       /* error */
370       if (bytes_read < 0)
371         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372                     _("Error reading from gnunet-peerinfo: %s\n"),
373                     STRERROR (errno));
374       else
375         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
376                     _("Malformed output from gnunet-peerinfo!\n"));
377       cb = d->cb;
378       d->cb = NULL;
379       GNUNET_DISK_pipe_close (d->pipe_stdout);
380       d->pipe_stdout = NULL;
381       (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
382       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
383       GNUNET_OS_process_close (d->proc);
384       d->proc = NULL;
385       if (NULL != cb)
386         cb (d->cb_cls, NULL, d->cfg, d, _("`Failed to get hostkey!\n"));
387       return;
388     }
389     d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id));
390     GNUNET_DISK_pipe_close (d->pipe_stdout);
391     d->pipe_stdout = NULL;
392     (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
393     GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
394     GNUNET_OS_process_close (d->proc);
395     d->proc = NULL;
396     d->have_hostkey = GNUNET_YES;
397     if (d->hostkey_callback != NULL)
398     {
399       d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL);
400       d->hostkey_callback = NULL;
401       d->phase = SP_HOSTKEY_CREATED;
402     }
403     else
404     {
405       d->phase = SP_TOPOLOGY_SETUP;
406     }
407 #if DEBUG_TESTING
408     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n");
409 #endif
410     /* Fall through */
411   case SP_HOSTKEY_CREATED:
412     /* wait for topology finished */
413     if ((GNUNET_YES == d->dead) ||
414         (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0))
415     {
416       cb = d->cb;
417       d->cb = NULL;
418       if (NULL != cb)
419         cb (d->cb_cls, NULL, d->cfg, d,
420             _("`Failed while waiting for topology setup!\n"));
421       return;
422     }
423
424     d->task =
425         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
426                                       d);
427     break;
428   case SP_TOPOLOGY_SETUP:      /* Indicates topology setup has completed! */
429     /* start GNUnet on remote host */
430     if (NULL == d->hostname)
431     {
432 #if DEBUG_TESTING
433       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
434                   "Starting `%s', with command `%s %s %s %s %s %s'.\n",
435                   "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-L", "DEBUG",
436                   "-s");
437 #endif
438       d->proc =
439           GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm", "-c",
440                                    d->cfgfile,
441 #if DEBUG_TESTING
442                                    "-L", "DEBUG",
443 #endif
444                                    "-s", "-q", "-T",
445                                    GNUNET_TIME_relative_to_string
446                                    (GNUNET_TIME_absolute_get_remaining
447                                     (d->max_timeout)), NULL);
448     }
449     else
450     {
451       if (d->username != NULL)
452         GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname);
453       else
454         dst = GNUNET_strdup (d->hostname);
455
456 #if DEBUG_TESTING
457       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
458                   "Starting `%s', with command `%s %s %s %s %s %s %s %s'.\n",
459                   "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile,
460                   "-L", "DEBUG", "-s", "-q");
461 #endif
462       if (d->ssh_port_str == NULL)
463       {
464         d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
465 #if !DEBUG_TESTING
466                                            "-q",
467 #endif
468                                            dst, "gnunet-arm",
469 #if DEBUG_TESTING
470                                            "-L", "DEBUG",
471 #endif
472                                            "-c", d->cfgfile, "-s", "-q", "-T",
473                                            GNUNET_TIME_relative_to_string
474                                            (GNUNET_TIME_absolute_get_remaining
475                                             (d->max_timeout)), NULL);
476       }
477       else
478       {
479
480         d->proc =
481             GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh", "-p",
482                                      d->ssh_port_str,
483 #if !DEBUG_TESTING
484                                      "-q",
485 #endif
486                                      dst, "gnunet-arm",
487 #if DEBUG_TESTING
488                                      "-L", "DEBUG",
489 #endif
490                                      "-c", d->cfgfile, "-s", "-q", "-T",
491                                      GNUNET_TIME_relative_to_string
492                                      (GNUNET_TIME_absolute_get_remaining
493                                       (d->max_timeout)), NULL);
494       }
495       GNUNET_free (dst);
496     }
497     if (NULL == d->proc)
498     {
499       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500                   _("Could not start `%s' process to start GNUnet.\n"),
501                   (NULL == d->hostname) ? "gnunet-arm" : "ssh");
502       cb = d->cb;
503       d->cb = NULL;
504       if (NULL != cb)
505         cb (d->cb_cls, NULL, d->cfg, d,
506             (NULL ==
507              d->hostname) ? _("Failed to start `gnunet-arm' process.\n") :
508             _("Failed to start `ssh' process.\n"));
509       return;
510     }
511 #if DEBUG_TESTING
512     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
513                 "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm",
514                 "gnunet-service-core");
515 #endif
516     d->phase = SP_START_ARMING;
517     d->task =
518         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
519                                       d);
520     break;
521   case SP_START_ARMING:
522     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
523     {
524       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
525       {
526         cb = d->cb;
527         d->cb = NULL;
528         if (NULL != cb)
529           cb (d->cb_cls, NULL, d->cfg, d,
530               (NULL ==
531                d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") :
532               _("`ssh' does not seem to terminate.\n"));
533         GNUNET_CONFIGURATION_destroy (d->cfg);
534         GNUNET_free (d->cfgfile);
535         GNUNET_free_non_null (d->hostname);
536         GNUNET_free_non_null (d->username);
537         GNUNET_free (d->proc);
538         GNUNET_free (d);
539         return;
540       }
541       /* wait some more */
542       d->task =
543           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
544                                         d);
545       return;
546     }
547 #if DEBUG_TESTING
548     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully started `%s'.\n",
549                 "gnunet-arm");
550 #endif
551     GNUNET_free (d->proc);
552     d->phase = SP_START_CORE;
553 #if DEBUG_TESTING
554     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Calling CORE_connect\n");
555 #endif
556     /* Fall through */
557   case SP_START_CORE:
558     if (d->server != NULL)
559       GNUNET_CORE_disconnect (d->server);
560
561     d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL);
562     if (d->th == NULL)
563     {
564       if (GNUNET_YES == d->dead)
565         GNUNET_TESTING_daemon_stop (d,
566                                     GNUNET_TIME_absolute_get_remaining
567                                     (d->max_timeout), d->dead_cb,
568                                     d->dead_cb_cls, GNUNET_YES, GNUNET_NO);
569       else if (NULL != d->cb)
570         d->cb (d->cb_cls, &d->id, d->cfg, d,
571                _("Failed to connect to transport service!\n"));
572       return;
573     }
574 #if DEBUG_TESTING
575     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                 "Connected to transport service `%s', getting HELLO\n",
577                 GNUNET_i2s (&d->id));
578 #endif
579
580     d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d);
581     /* FIXME: store task ID somewhere! */
582     GNUNET_SCHEDULER_add_now (&notify_daemon_started, d);
583     /*cb = d->cb;
584      * d->cb = NULL;
585      * if (NULL != cb)
586      * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */
587     d->running = GNUNET_YES;
588     d->phase = SP_GET_HELLO;
589     break;
590   case SP_GET_HELLO:
591     if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
592     {
593       if (d->server != NULL)
594         GNUNET_CORE_disconnect (d->server);
595       if (d->th != NULL)
596         GNUNET_TRANSPORT_disconnect (d->th);
597       cb = d->cb;
598       d->cb = NULL;
599       if (NULL != cb)
600         cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n"));
601       GNUNET_CONFIGURATION_destroy (d->cfg);
602       GNUNET_free (d->cfgfile);
603       GNUNET_free_non_null (d->hostname);
604       GNUNET_free_non_null (d->username);
605       GNUNET_free (d);
606       return;
607     }
608     if (d->hello != NULL)
609       return;
610     GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK);
611     d->task =
612         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
613                                       (GNUNET_CONSTANTS_SERVICE_RETRY, 2),
614                                       &start_fsm, d);
615     break;
616   case SP_START_DONE:
617     GNUNET_break (0);
618     break;
619   case SP_SERVICE_START:
620     /* confirm gnunet-arm exited */
621     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
622     {
623       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
624       {
625         cb = d->cb;
626         d->cb = NULL;
627         if (NULL != cb)
628           cb (d->cb_cls, NULL, d->cfg, d,
629               (NULL ==
630                d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") :
631               _("`ssh' does not seem to terminate.\n"));
632         return;
633       }
634       /* wait some more */
635       d->task =
636           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
637                                         d);
638       return;
639     }
640 #if EXTRA_CHECKS
641     if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
642     {
643       cb = d->cb;
644       d->cb = NULL;
645       if (NULL != cb)
646         cb (d->cb_cls, NULL, d->cfg, d,
647             (NULL ==
648              d->hostname) ?
649             _
650             ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n")
651             : _("`ssh' does not seem to terminate.\n"));
652       return;
653     }
654 #endif
655 #if DEBUG_TESTING
656     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n");
657 #endif
658     cb = d->cb;
659     d->cb = NULL;
660     d->phase = SP_START_DONE;
661     if (NULL != cb)
662       cb (d->cb_cls, &d->id, d->cfg, d, NULL);
663     break;
664   case SP_SERVICE_SHUTDOWN_START:
665     /* confirm copying complete */
666     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
667     {
668       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
669       {
670         if (NULL != d->dead_cb)
671           d->dead_cb (d->dead_cb_cls,
672                       _
673                       ("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
674         return;
675       }
676       /* wait some more */
677       d->task =
678           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
679                                         d);
680       return;
681     }
682 #if EXTRA_CHECKS
683     if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
684     {
685       if (NULL != d->dead_cb)
686         d->dead_cb (d->dead_cb_cls,
687                     _
688                     ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
689       return;
690     }
691 #endif
692 #if DEBUG_TESTING
693     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
694 #endif
695     if (NULL != d->dead_cb)
696       d->dead_cb (d->dead_cb_cls, NULL);
697     break;
698   case SP_SHUTDOWN_START:
699     /* confirm copying complete */
700     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
701     {
702       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)
703       {
704         if (NULL != d->dead_cb)
705           d->dead_cb (d->dead_cb_cls,
706                       _
707                       ("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
708         if (d->th != NULL)
709         {
710           GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
711           d->ghh = NULL;
712           GNUNET_TRANSPORT_disconnect (d->th);
713           d->th = NULL;
714         }
715         GNUNET_CONFIGURATION_destroy (d->cfg);
716         GNUNET_free (d->cfgfile);
717         GNUNET_free_non_null (d->hello);
718         GNUNET_free_non_null (d->hostname);
719         GNUNET_free_non_null (d->username);
720         GNUNET_free_non_null (d->shortname);
721         GNUNET_free_non_null (d->proc);
722         d->proc = NULL;
723         GNUNET_free (d);
724         return;
725       }
726       /* wait some more */
727       d->task =
728           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
729                                         d);
730       return;
731     }
732     if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
733     {
734       if (NULL != d->dead_cb)
735         d->dead_cb (d->dead_cb_cls,
736                     _
737                     ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
738       if (d->th != NULL)
739       {
740         GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
741         d->ghh = NULL;
742         GNUNET_TRANSPORT_disconnect (d->th);
743         d->th = NULL;
744       }
745       if (d->server != NULL)
746       {
747         GNUNET_CORE_disconnect (d->server);
748         d->server = NULL;
749       }
750       GNUNET_CONFIGURATION_destroy (d->cfg);
751       GNUNET_free (d->cfgfile);
752       GNUNET_free_non_null (d->hello);
753       GNUNET_free_non_null (d->hostname);
754       GNUNET_free_non_null (d->username);
755       GNUNET_free_non_null (d->shortname);
756       GNUNET_free_non_null (d->proc);
757       d->proc = NULL;
758       GNUNET_free (d);
759       return;
760     }
761 #if DEBUG_TESTING
762     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n");
763 #endif
764     if (d->server != NULL)
765     {
766       GNUNET_CORE_disconnect (d->server);
767       d->server = NULL;
768     }
769
770     if (d->th != NULL)
771     {
772       GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
773       d->ghh = NULL;
774       GNUNET_TRANSPORT_disconnect (d->th);
775       d->th = NULL;
776     }
777
778     if (NULL != d->dead_cb)
779       d->dead_cb (d->dead_cb_cls, NULL);
780
781     /* state clean up and notifications */
782     if (d->churn == GNUNET_NO)
783     {
784       GNUNET_CONFIGURATION_destroy (d->cfg);
785       GNUNET_free (d->cfgfile);
786       GNUNET_free_non_null (d->hostname);
787       GNUNET_free_non_null (d->username);
788     }
789
790     GNUNET_free_non_null (d->hello);
791     d->hello = NULL;
792     GNUNET_free_non_null (d->shortname);
793     GNUNET_free_non_null (d->proc);
794     d->proc = NULL;
795     d->shortname = NULL;
796     if (d->churn == GNUNET_NO)
797       GNUNET_free (d);
798
799     break;
800   case SP_CONFIG_UPDATE:
801     /* confirm copying complete */
802     if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
803     {
804       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)   /* FIXME: config update should take timeout parameter! */
805       {
806         cb = d->cb;
807         d->cb = NULL;
808         if (NULL != cb)
809           cb (d->cb_cls, NULL, d->cfg, d,
810               _("`scp' does not seem to terminate.\n"));
811         return;
812       }
813       /* wait some more */
814       d->task =
815           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
816                                         d);
817       return;
818     }
819     if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
820     {
821       if (NULL != d->update_cb)
822         d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n"));
823       return;
824     }
825 #if DEBUG_TESTING
826     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827                 "Successfully copied configuration file.\n");
828 #endif
829     if (NULL != d->update_cb)
830       d->update_cb (d->update_cb_cls, NULL);
831     d->phase = SP_START_DONE;
832     break;
833   }
834 }
835
836 /**
837  * Continues GNUnet daemon startup when user wanted to be notified
838  * once a hostkey was generated (for creating friends files, blacklists,
839  * etc.).
840  *
841  * @param daemon the daemon to finish starting
842  */
843 void
844 GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon)
845 {
846   GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED);
847   daemon->phase = SP_TOPOLOGY_SETUP;
848 }
849
850 /**
851  * Check whether the given daemon is running.
852  *
853  * @param daemon the daemon to check
854  *
855  * @return GNUNET_YES if the daemon is up, GNUNET_NO if the
856  *         daemon is down, GNUNET_SYSERR on error.
857  */
858 int
859 GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon)
860 {
861   if (daemon == NULL)
862     return GNUNET_SYSERR;
863
864   if (daemon->running == GNUNET_YES)
865     return GNUNET_YES;
866   return GNUNET_NO;
867 }
868
869
870 /**
871  * Starts a GNUnet daemon service which has been previously stopped.
872  *
873  * @param d the daemon for which the service should be started
874  * @param service the name of the service to start
875  * @param timeout how long to wait for process for shutdown to complete
876  * @param cb function called once the service starts
877  * @param cb_cls closure for cb
878  */
879 void
880 GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d,
881                                              char *service,
882                                              struct GNUNET_TIME_Relative
883                                              timeout,
884                                              GNUNET_TESTING_NotifyDaemonRunning
885                                              cb, void *cb_cls)
886 {
887   char *arg;
888
889   d->cb = cb;
890   d->cb_cls = cb_cls;
891
892   GNUNET_assert (d->running == GNUNET_YES);
893
894   if (d->phase == SP_CONFIG_UPDATE)
895   {
896     GNUNET_SCHEDULER_cancel (d->task);
897     d->phase = SP_START_DONE;
898   }
899
900   if (d->churned_services == NULL)
901   {
902     d->cb (d->cb_cls, &d->id, d->cfg, d,
903            "No service has been churned off yet!!");
904     return;
905   }
906   d->phase = SP_SERVICE_START;
907   GNUNET_free (d->churned_services);
908   d->churned_services = NULL;
909   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
910   /* Check if this is a local or remote process */
911   if (NULL != d->hostname)
912   {
913 #if DEBUG_TESTING
914     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915                 "Starting gnunet-arm with config `%s' on host `%s'.\n",
916                 d->cfgfile, d->hostname);
917 #endif
918
919     if (d->username != NULL)
920       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
921     else
922       arg = GNUNET_strdup (d->hostname);
923
924     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
925 #if !DEBUG_TESTING
926                                        "-q",
927 #endif
928                                        arg, "gnunet-arm",
929 #if DEBUG_TESTING
930                                        "-L", "DEBUG",
931 #endif
932                                        "-c", d->cfgfile, "-i", service, "-q",
933                                        "-T",
934                                        GNUNET_TIME_relative_to_string (timeout),
935                                        NULL);
936     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937                 "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n",
938                 arg, "gnunet-arm", d->cfgfile, service);
939     GNUNET_free (arg);
940   }
941   else
942   {
943 #if DEBUG_TESTING
944     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
945                 "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile);
946 #endif
947     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
948 #if DEBUG_TESTING
949                                        "-L", "DEBUG",
950 #endif
951                                        "-c", d->cfgfile, "-i", service, "-q",
952                                        "-T",
953                                        GNUNET_TIME_relative_to_string (timeout),
954                                        NULL);
955   }
956
957   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
958   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
959 }
960
961 /**
962  * Starts a GNUnet daemon's service.
963  *
964  * @param d the daemon for which the service should be started
965  * @param service the name of the service to start
966  * @param timeout how long to wait for process for startup
967  * @param cb function called once gnunet-arm returns
968  * @param cb_cls closure for cb
969  */
970 void
971 GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d,
972                                      const char *service,
973                                      struct GNUNET_TIME_Relative timeout,
974                                      GNUNET_TESTING_NotifyDaemonRunning cb,
975                                      void *cb_cls)
976 {
977   char *arg;
978
979   d->cb = cb;
980   d->cb_cls = cb_cls;
981
982   GNUNET_assert (service != NULL);
983   GNUNET_assert (d->running == GNUNET_YES);
984   GNUNET_assert (d->phase == SP_START_DONE);
985
986 #if DEBUG_TESTING
987   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988               _("Starting service %s for peer `%4s'\n"), service,
989               GNUNET_i2s (&d->id));
990 #endif
991
992   d->phase = SP_SERVICE_START;
993   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
994   /* Check if this is a local or remote process */
995   if (NULL != d->hostname)
996   {
997 #if DEBUG_TESTING
998     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999                 "Starting gnunet-arm with config `%s' on host `%s'.\n",
1000                 d->cfgfile, d->hostname);
1001 #endif
1002
1003     if (d->username != NULL)
1004       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1005     else
1006       arg = GNUNET_strdup (d->hostname);
1007
1008     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1009 #if !DEBUG_TESTING
1010                                        "-q",
1011 #endif
1012                                        arg, "gnunet-arm",
1013 #if DEBUG_TESTING
1014                                        "-L", "DEBUG",
1015 #endif
1016                                        "-c", d->cfgfile, "-i", service, "-q",
1017                                        "-T",
1018                                        GNUNET_TIME_relative_to_string (timeout),
1019                                        NULL);
1020     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021                 "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n",
1022                 arg, "gnunet-arm", d->cfgfile, service,
1023                 GNUNET_TIME_relative_to_string (timeout));
1024     GNUNET_free (arg);
1025   }
1026   else
1027   {
1028 #if DEBUG_TESTING
1029     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1030                 "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile);
1031 #endif
1032     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1033 #if DEBUG_TESTING
1034                                        "-L", "DEBUG",
1035 #endif
1036                                        "-c", d->cfgfile, "-i", service, "-q",
1037                                        "-T",
1038                                        GNUNET_TIME_relative_to_string (timeout),
1039                                        NULL);
1040     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1041                 "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n",
1042                 "gnunet-arm", d->cfgfile, service,
1043                 GNUNET_TIME_relative_to_string (timeout));
1044   }
1045
1046   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1047   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1048 }
1049
1050 /**
1051  * Start a peer that has previously been stopped using the daemon_stop
1052  * call (and files weren't deleted and the allow restart flag)
1053  *
1054  * @param daemon the daemon to start (has been previously stopped)
1055  * @param timeout how long to wait for restart
1056  * @param cb the callback for notification when the peer is running
1057  * @param cb_cls closure for the callback
1058  */
1059 void
1060 GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon,
1061                                      struct GNUNET_TIME_Relative timeout,
1062                                      GNUNET_TESTING_NotifyDaemonRunning cb,
1063                                      void *cb_cls)
1064 {
1065   if (daemon->running == GNUNET_YES)
1066   {
1067     cb (cb_cls, &daemon->id, daemon->cfg, daemon,
1068         "Daemon already running, can't restart!");
1069     return;
1070   }
1071
1072   daemon->cb = cb;
1073   daemon->cb_cls = cb_cls;
1074   daemon->phase = SP_TOPOLOGY_SETUP;
1075   daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1076   /* FIXME: why add_continuation? */
1077   GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon,
1078                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1079 }
1080
1081 /**
1082  * Starts a GNUnet daemon.  GNUnet must be installed on the target
1083  * system and available in the PATH.  The machine must furthermore be
1084  * reachable via "ssh" (unless the hostname is "NULL") without the
1085  * need to enter a password.
1086  *
1087  * @param cfg configuration to use
1088  * @param timeout how long to wait starting up peers
1089  * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO
1090  *                to really start the peer (default)
1091  * @param hostname name of the machine where to run GNUnet
1092  *        (use NULL for localhost).
1093  * @param ssh_username ssh username to use when connecting to hostname
1094  * @param sshport port to pass to ssh process when connecting to hostname
1095  * @param hostkey pointer to a hostkey to be written to disk (instead of being generated)
1096  * @param hostkey_callback function to call once the hostkey has been
1097  *        generated for this peer, but it hasn't yet been started
1098  *        (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start)
1099  * @param hostkey_cls closure for hostkey callback
1100  * @param cb function to call once peer is up, or failed to start
1101  * @param cb_cls closure for cb
1102  * @return handle to the daemon (actual start will be completed asynchronously)
1103  */
1104 struct GNUNET_TESTING_Daemon *
1105 GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
1106                              struct GNUNET_TIME_Relative timeout, int pretend,
1107                              const char *hostname, const char *ssh_username,
1108                              uint16_t sshport, const char *hostkey,
1109                              GNUNET_TESTING_NotifyHostkeyCreated
1110                              hostkey_callback, void *hostkey_cls,
1111                              GNUNET_TESTING_NotifyDaemonRunning cb,
1112                              void *cb_cls)
1113 {
1114   struct GNUNET_TESTING_Daemon *ret;
1115   char *arg;
1116   char *username;
1117   char *servicehome;
1118   char *baseservicehome;
1119   char *slash;
1120   char *hostkeyfile;
1121   char *temp_file_name;
1122   struct GNUNET_DISK_FileHandle *fn;
1123   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
1124   struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
1125
1126   ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon));
1127   ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
1128   if (sshport != 0)
1129   {
1130     GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport);
1131   }
1132   else
1133     ret->ssh_port_str = NULL;
1134
1135   /* Find service home and base service home directories, create it if it doesn't exist */
1136   GNUNET_assert (GNUNET_OK ==
1137                  GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
1138                                                         "SERVICEHOME",
1139                                                         &servicehome));
1140
1141   GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome));
1142   GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome);
1143   ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name);
1144   GNUNET_free (temp_file_name);
1145 #if DEBUG_TESTING
1146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147               "Setting up peer with configuration file `%s'.\n", ret->cfgfile);
1148 #endif
1149   if (NULL == ret->cfgfile)
1150   {
1151     GNUNET_free_non_null (ret->ssh_port_str);
1152     GNUNET_free_non_null (ret->hostname);
1153     GNUNET_free (ret);
1154     return NULL;
1155   }
1156   ret->hostkey_callback = hostkey_callback;
1157   ret->hostkey_cls = hostkey_cls;
1158   ret->cb = cb;
1159   ret->cb_cls = cb_cls;
1160   ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1161   ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
1162   GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG",
1163                                          ret->cfgfile);
1164
1165   if (hostkey != NULL)          /* Get the peer identity from the hostkey */
1166   {
1167     private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE);
1168     GNUNET_assert (private_key != NULL);
1169     GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
1170     GNUNET_CRYPTO_hash (&public_key,
1171                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1172                         &ret->id.hashPubKey);
1173     ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id));
1174     ret->have_hostkey = GNUNET_YES;
1175     GNUNET_CRYPTO_rsa_key_free (private_key);
1176   }
1177
1178   /* Write hostkey to file, if we were given one */
1179   hostkeyfile = NULL;
1180   if (hostkey != NULL)
1181   {
1182     GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome);
1183     fn = GNUNET_DISK_file_open (hostkeyfile,
1184                                 GNUNET_DISK_OPEN_READWRITE |
1185                                 GNUNET_DISK_OPEN_CREATE,
1186                                 GNUNET_DISK_PERM_USER_READ |
1187                                 GNUNET_DISK_PERM_USER_WRITE);
1188     GNUNET_assert (fn != NULL);
1189     GNUNET_assert (HOSTKEYFILESIZE ==
1190                    GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE));
1191     GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn));
1192   }
1193
1194   /* write configuration to temporary file */
1195   if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile))
1196   {
1197     if (0 != UNLINK (ret->cfgfile))
1198       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
1199                                 ret->cfgfile);
1200     GNUNET_CONFIGURATION_destroy (ret->cfg);
1201     GNUNET_free_non_null (ret->hostname);
1202     GNUNET_free (ret->cfgfile);
1203     GNUNET_free (ret);
1204     return NULL;
1205   }
1206   if (ssh_username != NULL)
1207     username = GNUNET_strdup (ssh_username);
1208   if ((ssh_username == NULL) &&
1209       (GNUNET_OK !=
1210        GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "USERNAME",
1211                                               &username)))
1212   {
1213     if (NULL != getenv ("USER"))
1214       username = GNUNET_strdup (getenv ("USER"));
1215     else
1216       username = NULL;
1217   }
1218   ret->username = username;
1219
1220   if (GNUNET_NO == pretend)     /* Copy files, enter finite state machine */
1221   {
1222     /* copy directory to remote host */
1223     if (NULL != hostname)
1224     {
1225 #if DEBUG_TESTING
1226       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227                   "Copying configuration directory to host `%s'.\n", hostname);
1228 #endif
1229       baseservicehome = GNUNET_strdup (servicehome);
1230       /* Remove trailing /'s */
1231       while (baseservicehome[strlen (baseservicehome) - 1] == '/')
1232         baseservicehome[strlen (baseservicehome) - 1] = '\0';
1233       /* Find next directory /, jump one ahead */
1234       slash = strrchr (baseservicehome, '/');
1235       if (slash != NULL)
1236         *(++slash) = '\0';
1237
1238       ret->phase = SP_COPYING;
1239       if (NULL != username)
1240         GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome);
1241       else
1242         GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome);
1243       GNUNET_free (baseservicehome);
1244       if (ret->ssh_port_str == NULL)
1245       {
1246         ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp", "-r",
1247 #if !DEBUG_TESTING
1248                                              "-q",
1249 #endif
1250                                              servicehome, arg, NULL);
1251 #if DEBUG_TESTING
1252         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1253                     "copying directory with command scp -r %s %s\n",
1254                     servicehome, arg);
1255 #endif
1256       }
1257       else
1258       {
1259         ret->proc =
1260             GNUNET_OS_start_process (NULL, NULL, "scp", "scp", "-r", "-P",
1261                                      ret->ssh_port_str,
1262 #if !DEBUG_TESTING
1263                                      "-q",
1264 #endif
1265                                      servicehome, arg, NULL);
1266       }
1267       GNUNET_free (arg);
1268       if (NULL == ret->proc)
1269       {
1270         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1271                     _
1272                     ("Could not start `%s' process to copy configuration directory.\n"),
1273                     "scp");
1274         if (0 != UNLINK (ret->cfgfile))
1275           GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
1276                                     ret->cfgfile);
1277         GNUNET_CONFIGURATION_destroy (ret->cfg);
1278         GNUNET_free_non_null (ret->hostname);
1279         GNUNET_free_non_null (ret->username);
1280         GNUNET_free (ret->cfgfile);
1281         GNUNET_free (ret);
1282         if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile)))
1283           GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
1284                                     hostkeyfile);
1285         GNUNET_free_non_null (hostkeyfile);
1286         GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome));
1287         GNUNET_free (servicehome);
1288         return NULL;
1289       }
1290
1291       ret->task =
1292           GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm,
1293                                         ret);
1294       GNUNET_free_non_null (hostkeyfile);
1295       GNUNET_free (servicehome);
1296       return ret;
1297     }
1298 #if DEBUG_TESTING
1299     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1300                 "No need to copy configuration file since we are running locally.\n");
1301 #endif
1302     ret->phase = SP_COPIED;
1303     /* FIXME: why add_cont? */
1304     GNUNET_SCHEDULER_add_continuation (&start_fsm, ret,
1305                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1306   }
1307   GNUNET_free_non_null (hostkeyfile);
1308   GNUNET_free (servicehome);
1309   return ret;
1310 }
1311
1312
1313 /**
1314  * Restart (stop and start) a GNUnet daemon.
1315  *
1316  * @param d the daemon that should be restarted
1317  * @param cb function called once the daemon is (re)started
1318  * @param cb_cls closure for cb
1319  */
1320 void
1321 GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d,
1322                                GNUNET_TESTING_NotifyDaemonRunning cb,
1323                                void *cb_cls)
1324 {
1325   char *arg;
1326   char *del_arg;
1327
1328   del_arg = NULL;
1329   if (NULL != d->cb)
1330   {
1331     d->dead = GNUNET_YES;
1332     return;
1333   }
1334
1335   d->cb = cb;
1336   d->cb_cls = cb_cls;
1337
1338   if (d->phase == SP_CONFIG_UPDATE)
1339   {
1340     GNUNET_SCHEDULER_cancel (d->task);
1341     d->phase = SP_START_DONE;
1342   }
1343   if (d->server != NULL)
1344   {
1345     GNUNET_CORE_disconnect (d->server);
1346     d->server = NULL;
1347   }
1348
1349   if (d->th != NULL)
1350   {
1351     GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
1352     d->ghh = NULL;
1353     GNUNET_TRANSPORT_disconnect (d->th);
1354     d->th = NULL;
1355   }
1356   /* state clean up and notifications */
1357   GNUNET_free_non_null (d->hello);
1358
1359 #if DEBUG_TESTING
1360   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"),
1361               GNUNET_i2s (&d->id));
1362 #endif
1363
1364   d->phase = SP_START_ARMING;
1365
1366   /* Check if this is a local or remote process */
1367   if (NULL != d->hostname)
1368   {
1369 #if DEBUG_TESTING
1370     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371                 "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1372                 d->cfgfile, d->hostname);
1373 #endif
1374
1375     if (d->username != NULL)
1376       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1377     else
1378       arg = GNUNET_strdup (d->hostname);
1379
1380     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1381 #if !DEBUG_TESTING
1382                                        "-q",
1383 #endif
1384                                        arg, "gnunet-arm",
1385 #if DEBUG_TESTING
1386                                        "-L", "DEBUG",
1387 #endif
1388                                        "-c", d->cfgfile, "-e", "-r", NULL);
1389     /* Use -r to restart arm and all services */
1390
1391     GNUNET_free (arg);
1392   }
1393   else
1394   {
1395 #if DEBUG_TESTING
1396     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1397                 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
1398 #endif
1399     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1400 #if DEBUG_TESTING
1401                                        "-L", "DEBUG",
1402 #endif
1403                                        "-c", d->cfgfile, "-e", "-r", NULL);
1404   }
1405
1406   GNUNET_free_non_null (del_arg);
1407   d->task =
1408       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d);
1409
1410 }
1411
1412
1413 /**
1414  * Stops a GNUnet daemon.
1415  *
1416  * @param d the daemon that should be stopped
1417  * @param service the name of the service to stop
1418  * @param timeout how long to wait for process for shutdown to complete
1419  * @param cb function called once the daemon was stopped
1420  * @param cb_cls closure for cb
1421  */
1422 void
1423 GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d,
1424                                     const char *service,
1425                                     struct GNUNET_TIME_Relative timeout,
1426                                     GNUNET_TESTING_NotifyCompletion cb,
1427                                     void *cb_cls)
1428 {
1429   char *arg;
1430
1431   d->dead_cb = cb;
1432   d->dead_cb_cls = cb_cls;
1433
1434   GNUNET_assert (d->running == GNUNET_YES);
1435
1436   if (d->phase == SP_CONFIG_UPDATE)
1437   {
1438     GNUNET_SCHEDULER_cancel (d->task);
1439     d->phase = SP_START_DONE;
1440   }
1441
1442 #if DEBUG_TESTING
1443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"),
1444               GNUNET_i2s (&d->id));
1445 #endif
1446   if (d->churned_services != NULL)
1447   {
1448     d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!");
1449     return;
1450   }
1451   d->phase = SP_SERVICE_SHUTDOWN_START;
1452   d->churned_services = GNUNET_strdup (service);
1453   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1454   /* Check if this is a local or remote process */
1455   if (NULL != d->hostname)
1456   {
1457 #if DEBUG_TESTING
1458     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459                 "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1460                 d->cfgfile, d->hostname);
1461 #endif
1462
1463     if (d->username != NULL)
1464       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1465     else
1466       arg = GNUNET_strdup (d->hostname);
1467
1468     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1469 #if !DEBUG_TESTING
1470                                        "-q",
1471 #endif
1472                                        arg, "gnunet-arm",
1473 #if DEBUG_TESTING
1474                                        "-L", "DEBUG",
1475 #endif
1476                                        "-c", d->cfgfile, "-k", service, "-q",
1477                                        "-T",
1478                                        GNUNET_TIME_relative_to_string (timeout),
1479                                        NULL);
1480     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1481                 "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n",
1482                 arg, "gnunet-arm", d->cfgfile, service);
1483     GNUNET_free (arg);
1484   }
1485   else
1486   {
1487 #if DEBUG_TESTING
1488     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1489                 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
1490 #endif
1491     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1492 #if DEBUG_TESTING
1493                                        "-L", "DEBUG",
1494 #endif
1495                                        "-c", d->cfgfile, "-k", service, "-q",
1496                                        "-T",
1497                                        GNUNET_TIME_relative_to_string (timeout),
1498                                        NULL);
1499   }
1500
1501   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1502   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1503 }
1504
1505
1506 /**
1507  * Stops a GNUnet daemon.
1508  *
1509  * @param d the daemon that should be stopped
1510  * @param timeout how long to wait for process for shutdown to complete
1511  * @param cb function called once the daemon was stopped
1512  * @param cb_cls closure for cb
1513  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1514  *        to leave them
1515  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1516  *        GNUNET_NO to kill off and clean up for good
1517  */
1518 void
1519 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
1520                             struct GNUNET_TIME_Relative timeout,
1521                             GNUNET_TESTING_NotifyCompletion cb, void *cb_cls,
1522                             int delete_files, int allow_restart)
1523 {
1524   char *arg;
1525   char *del_arg;
1526
1527   d->dead_cb = cb;
1528   d->dead_cb_cls = cb_cls;
1529
1530   if (NULL != d->cb)
1531   {
1532 #if DEBUG_TESTING
1533     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"),
1534                 GNUNET_i2s (&d->id));
1535 #endif
1536     d->dead = GNUNET_YES;
1537     return;
1538   }
1539
1540   if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES))    /* Peer has already been stopped in churn context! */
1541   {
1542     /* Free what was left from churning! */
1543     GNUNET_assert (d->cfg != NULL);
1544     GNUNET_CONFIGURATION_destroy (d->cfg);
1545     if (delete_files == GNUNET_YES)
1546     {
1547       if (0 != UNLINK (d->cfgfile))
1548       {
1549         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink");
1550       }
1551     }
1552     GNUNET_free (d->cfgfile);
1553     GNUNET_free_non_null (d->hostname);
1554     GNUNET_free_non_null (d->username);
1555     if (NULL != d->dead_cb)
1556       d->dead_cb (d->dead_cb_cls, NULL);
1557     GNUNET_free (d);
1558     return;
1559   }
1560
1561   del_arg = NULL;
1562   if (delete_files == GNUNET_YES)
1563   {
1564     GNUNET_asprintf (&del_arg, "-d");
1565   }
1566
1567   if (d->phase == SP_CONFIG_UPDATE)
1568   {
1569     GNUNET_SCHEDULER_cancel (d->task);
1570     d->phase = SP_START_DONE;
1571   }
1572   /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop?
1573   if (d->server != NULL)
1574     {
1575       GNUNET_CORE_disconnect (d->server);
1576       d->server = NULL;
1577     }
1578     */
1579   /* shutdown ARM process (will terminate others) */
1580 #if DEBUG_TESTING
1581   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"),
1582               GNUNET_i2s (&d->id));
1583 #endif
1584   d->phase = SP_SHUTDOWN_START;
1585   d->running = GNUNET_NO;
1586   if (allow_restart == GNUNET_YES)
1587     d->churn = GNUNET_YES;
1588   if (d->th != NULL)
1589   {
1590     GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
1591     d->ghh = NULL;
1592     GNUNET_TRANSPORT_disconnect (d->th);
1593     d->th = NULL;
1594   }
1595   /* Check if this is a local or remote process */
1596   if (NULL != d->hostname)
1597   {
1598 #if DEBUG_TESTING
1599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1600                 "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1601                 d->cfgfile, d->hostname);
1602 #endif
1603
1604     if (d->username != NULL)
1605       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1606     else
1607       arg = GNUNET_strdup (d->hostname);
1608
1609     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1610 #if !DEBUG_TESTING
1611                                        "-q",
1612 #endif
1613                                        arg, "gnunet-arm",
1614 #if DEBUG_TESTING
1615                                        "-L", "DEBUG",
1616 #endif
1617                                        "-c", d->cfgfile, "-e", "-q", "-T",
1618                                        GNUNET_TIME_relative_to_string (timeout),
1619                                        del_arg, NULL);
1620     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621                 "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n",
1622                 arg, "gnunet-arm", d->cfgfile, del_arg);
1623     /* Use -e to end arm, and -d to remove temp files */
1624     GNUNET_free (arg);
1625   }
1626   else
1627   {
1628 #if DEBUG_TESTING
1629     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1630                 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
1631 #endif
1632     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1633 #if DEBUG_TESTING
1634                                        "-L", "DEBUG",
1635 #endif
1636                                        "-c", d->cfgfile, "-e", "-q", "-T",
1637                                        GNUNET_TIME_relative_to_string (timeout),
1638                                        del_arg, NULL);
1639   }
1640
1641   GNUNET_free_non_null (del_arg);
1642   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1643   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1644 }
1645
1646
1647 /**
1648  * Changes the configuration of a GNUnet daemon.
1649  *
1650  * @param d the daemon that should be modified
1651  * @param cfg the new configuration for the daemon
1652  * @param cb function called once the configuration was changed
1653  * @param cb_cls closure for cb
1654  */
1655 void
1656 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
1657                                    struct GNUNET_CONFIGURATION_Handle *cfg,
1658                                    GNUNET_TESTING_NotifyCompletion cb,
1659                                    void *cb_cls)
1660 {
1661   char *arg;
1662
1663   if (d->phase != SP_START_DONE)
1664   {
1665     if (NULL != cb)
1666       cb (cb_cls,
1667           _
1668           ("Peer not yet running, can not change configuration at this point."));
1669     return;
1670   }
1671
1672   /* 1) write configuration to temporary file */
1673   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
1674   {
1675     if (NULL != cb)
1676       cb (cb_cls, _("Failed to write new configuration to disk."));
1677     return;
1678   }
1679
1680   /* 2) copy file to remote host (if necessary) */
1681   if (NULL == d->hostname)
1682   {
1683     /* signal success */
1684     if (NULL != cb)
1685       cb (cb_cls, NULL);
1686     return;
1687   }
1688 #if DEBUG_TESTING
1689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1690               "Copying updated configuration file to remote host `%s'.\n",
1691               d->hostname);
1692 #endif
1693   d->phase = SP_CONFIG_UPDATE;
1694   if (NULL != d->username)
1695     GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
1696   else
1697     GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
1698   d->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
1699 #if !DEBUG_TESTING
1700                                      "-q",
1701 #endif
1702                                      d->cfgfile, arg, NULL);
1703   GNUNET_free (arg);
1704   if (NULL == d->proc)
1705   {
1706     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1707                 _("Could not start `%s' process to copy configuration file.\n"),
1708                 "scp");
1709     if (NULL != cb)
1710       cb (cb_cls, _("Failed to copy new configuration to remote machine."));
1711     d->phase = SP_START_DONE;
1712     return;
1713   }
1714   d->update_cb = cb;
1715   d->update_cb_cls = cb_cls;
1716   d->task =
1717       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d);
1718 }
1719
1720
1721 /**
1722  * Data kept for each pair of peers that we try
1723  * to connect.
1724  */
1725 struct GNUNET_TESTING_ConnectContext
1726 {
1727   /**
1728    * Testing handle to the first daemon.
1729    */
1730   struct GNUNET_TESTING_Daemon *d1;
1731
1732   /**
1733    * Handle to core of first daemon (to check connect)
1734    */
1735   struct GNUNET_CORE_Handle *d1core;
1736
1737   /**
1738    * Have we actually connected to the core of the first daemon yet?
1739    */
1740   int d1core_ready;
1741
1742   /**
1743    * Testing handle to the second daemon.
1744    */
1745   struct GNUNET_TESTING_Daemon *d2;
1746
1747   /**
1748    * Handler for the request to core to connect to this peer.
1749    */
1750   struct GNUNET_CORE_PeerRequestHandle *connect_request_handle;
1751
1752   /**
1753    * Transport handle to the first daemon (to offer the HELLO of the second daemon to).
1754    */
1755   struct GNUNET_TRANSPORT_Handle *d1th;
1756
1757   /**
1758    * Function to call once we are done (or have timed out).
1759    */
1760   GNUNET_TESTING_NotifyConnection cb;
1761
1762   /**
1763    * Closure for "nb".
1764    */
1765   void *cb_cls;
1766
1767   /**
1768    * The relative timeout from whence this connect attempt was
1769    * started.  Allows for reconnect attempts.
1770    */
1771   struct GNUNET_TIME_Relative relative_timeout;
1772
1773   /**
1774    * Maximum number of connect attempts, will retry connection
1775    * this number of times on failures.
1776    */
1777   unsigned int connect_attempts;
1778
1779   /**
1780    * Hello timeout task
1781    */
1782   GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
1783
1784   /**
1785    * Connect timeout task
1786    */
1787   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1788
1789   /**
1790    * When should this operation be complete (or we must trigger
1791    * a timeout).
1792    */
1793   struct GNUNET_TIME_Relative timeout_hello;
1794
1795   /**
1796    * Was the connection attempt successful?
1797    */
1798   int connected;
1799
1800   /**
1801    * When connecting, do we need to send the HELLO?
1802    */
1803   int send_hello;
1804
1805   /**
1806    * The distance between the two connected peers
1807    */
1808   uint32_t distance;
1809 };
1810
1811
1812 /** Forward declaration **/
1813 static void
1814 reattempt_daemons_connect (void *cls,
1815                            const struct GNUNET_SCHEDULER_TaskContext *tc);
1816
1817
1818 /**
1819  * Notify callback about success or failure of the attempt
1820  * to connect the two peers
1821  *
1822  * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed)
1823  * @param tc reason tells us if we succeeded or failed
1824  */
1825 static void
1826 notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1827 {
1828   struct GNUNET_TESTING_ConnectContext *ctx = cls;
1829
1830   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1831   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1832   {
1833     GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1834     ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1835   }
1836
1837   if (ctx->connect_request_handle != NULL)
1838   {
1839     GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle);
1840     ctx->connect_request_handle = NULL;
1841   }
1842
1843   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1844   {
1845     if (ctx->d1th != NULL)
1846       GNUNET_TRANSPORT_disconnect (ctx->d1th);
1847     ctx->d1th = NULL;
1848     if (ctx->d1core != NULL)
1849       GNUNET_CORE_disconnect (ctx->d1core);
1850     ctx->d1core = NULL;
1851     GNUNET_free (ctx);
1852     return;
1853   }
1854
1855   if (ctx->d1th != NULL)
1856     GNUNET_TRANSPORT_disconnect (ctx->d1th);
1857   ctx->d1th = NULL;
1858   if (ctx->d1core != NULL)
1859     GNUNET_CORE_disconnect (ctx->d1core);
1860   ctx->d1core = NULL;
1861
1862   if (ctx->connected == GNUNET_YES)
1863   {
1864     if (ctx->cb != NULL)
1865     {
1866       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance,
1867                ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
1868     }
1869   }
1870   else if (ctx->connect_attempts > 0)
1871   {
1872     ctx->d1core_ready = GNUNET_NO;
1873     ctx->timeout_task = GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx);
1874     return;
1875   }
1876   else
1877   {
1878     if (ctx->cb != NULL)
1879     {
1880       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1881                ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect"));
1882     }
1883   }
1884   GNUNET_free (ctx);
1885 }
1886
1887
1888 /**
1889  * Success, connection is up.  Signal client our success.
1890  *
1891  * @param cls our "struct GNUNET_TESTING_ConnectContext"
1892  * @param peer identity of the peer that has connected
1893  * @param atsi performance information
1894  *
1895  */
1896 static void
1897 connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer,
1898                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1899 {
1900   struct GNUNET_TESTING_ConnectContext *ctx = cls;
1901
1902 #if DEBUG_TESTING
1903   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Connected peer %s to peer %s\n",
1904               ctx->d1->shortname, GNUNET_i2s (peer));
1905 #endif
1906
1907   if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))
1908     return;
1909   ctx->connected = GNUNET_YES;
1910   ctx->distance = 0;          /* FIXME: distance */
1911   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1912     {
1913       GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1914       ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1915     }
1916   GNUNET_SCHEDULER_cancel (ctx->timeout_task);
1917   ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
1918 }
1919
1920 /**
1921  * Task called once a core connect request has been transmitted.
1922  *
1923  * @param cls struct GNUNET_TESTING_ConnectContext
1924  * @param success was the request successful?
1925  */
1926 void
1927 core_connect_request_cont (void *cls, int success)
1928 {
1929   struct GNUNET_TESTING_ConnectContext *ctx = cls;
1930
1931   ctx->connect_request_handle = NULL;
1932 }
1933
1934 static void
1935 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1936 {
1937   struct GNUNET_TESTING_ConnectContext *ctx = cls;
1938   struct GNUNET_MessageHeader *hello;
1939
1940   ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1941   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1942     return;
1943   if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) &&
1944       (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) &&
1945       (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE))
1946   {
1947     hello = GNUNET_HELLO_get_header (ctx->d2->hello);
1948     GNUNET_assert (hello != NULL);
1949 #if DEBUG_TESTING
1950     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n",
1951                 ctx->d2->shortname, ctx->d1->shortname);
1952 #endif
1953     GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL);
1954     GNUNET_assert (ctx->d1core != NULL);
1955     ctx->connect_request_handle =
1956         GNUNET_CORE_peer_request_connect (ctx->d1core, &ctx->d2->id,
1957                                           &core_connect_request_cont, ctx);
1958
1959 #if DEBUG_TESTING
1960     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1961                 "Sending connect request to CORE of %s for peer %s\n",
1962                 GNUNET_i2s (&ctx->d1->id),
1963                 GNUNET_h2s (&ctx->d2->id.hashPubKey));
1964 #endif
1965     ctx->timeout_hello =
1966         GNUNET_TIME_relative_add (ctx->timeout_hello,
1967                                   GNUNET_TIME_relative_multiply
1968                                   (GNUNET_TIME_UNIT_MILLISECONDS, 500));
1969   }
1970   ctx->hello_send_task =
1971       GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx);
1972 }
1973
1974 /**
1975  * Notify of a successful connection to the core service.
1976  *
1977  * @param cls a ConnectContext
1978  * @param server handle to the core service
1979  * @param my_identity the peer identity of this peer
1980  * @param publicKey the public key of the peer
1981  */
1982 void
1983 core_init_notify (void *cls, struct GNUNET_CORE_Handle *server,
1984                   const struct GNUNET_PeerIdentity *my_identity,
1985                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
1986                   *publicKey)
1987 {
1988   struct GNUNET_TESTING_ConnectContext *connect_ctx = cls;
1989
1990   connect_ctx->d1core_ready = GNUNET_YES;
1991
1992   if (connect_ctx->send_hello == GNUNET_NO)
1993   {
1994     connect_ctx->connect_request_handle =
1995         GNUNET_CORE_peer_request_connect (connect_ctx->d1core,
1996                                           &connect_ctx->d2->id,
1997                                           &core_connect_request_cont,
1998                                           connect_ctx);
1999     GNUNET_assert (connect_ctx->connect_request_handle != NULL);
2000 #if DEBUG_TESTING
2001     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2002                 "Sending connect request to CORE of %s for peer %s\n",
2003                 connect_ctx->d1->shortname, connect_ctx->d2->shortname);
2004 #endif
2005   }
2006
2007 }
2008
2009
2010 static void
2011 reattempt_daemons_connect (void *cls,
2012                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2013 {
2014   struct GNUNET_TESTING_ConnectContext *ctx = cls;
2015
2016   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2017   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2018     return;
2019 #if DEBUG_TESTING_RECONNECT
2020   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2021               "re-attempting connect of peer %s to peer %s\n",
2022               ctx->d1->shortname, ctx->d2->shortname);
2023 #endif
2024   ctx->connect_attempts--;
2025   GNUNET_assert (ctx->d1core == NULL);
2026   ctx->d1core_ready = GNUNET_NO;
2027   ctx->d1core =
2028       GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify,
2029                            &connect_notify, NULL, NULL, NULL, GNUNET_NO, NULL,
2030                            GNUNET_NO, no_handlers);
2031   if (ctx->d1core == NULL)
2032   {
2033     if (NULL != ctx->cb)
2034       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2035                ctx->d2->cfg, ctx->d1, ctx->d2,
2036                _("Failed to connect to core service of first peer!\n"));
2037     GNUNET_free (ctx);
2038     return;
2039   }
2040
2041   /* Don't know reason for initial connect failure, update the HELLO for the second peer */
2042   if (NULL != ctx->d2->hello)
2043   {
2044     GNUNET_free (ctx->d2->hello);
2045     ctx->d2->hello = NULL;
2046     if (NULL != ctx->d2->th)
2047     {
2048       GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh);
2049       ctx->d2->ghh = NULL;
2050       GNUNET_TRANSPORT_disconnect (ctx->d2->th);
2051     }
2052     ctx->d2->th =
2053         GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL,
2054                                   NULL);
2055     GNUNET_assert (ctx->d2->th != NULL);
2056     ctx->d2->ghh =
2057         GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2058   }
2059
2060   if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL))
2061   {
2062     ctx->d2->th =
2063         GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL,
2064                                   NULL);
2065     if (ctx->d2->th == NULL)
2066     {
2067       GNUNET_CORE_disconnect (ctx->d1core);
2068       GNUNET_free (ctx);
2069       if (NULL != ctx->cb)
2070         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2071                  ctx->d2->cfg, ctx->d1, ctx->d2,
2072                  _("Failed to connect to transport service!\n"));
2073       return;
2074     }
2075     ctx->d2->ghh =
2076         GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2077   }
2078
2079   if (ctx->send_hello == GNUNET_YES)
2080   {
2081     ctx->d1th =
2082         GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL,
2083                                   NULL, NULL);
2084     if (ctx->d1th == NULL)
2085     {
2086       GNUNET_CORE_disconnect (ctx->d1core);
2087       GNUNET_free (ctx);
2088       if (NULL != ctx->cb)
2089         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2090                  ctx->d2->cfg, ctx->d1, ctx->d2,
2091                  _("Failed to connect to transport service!\n"));
2092       return;
2093     }
2094     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task);
2095     ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2096   }
2097   else
2098   {
2099     ctx->connect_request_handle =
2100         GNUNET_CORE_peer_request_connect (ctx->d1core, &ctx->d2->id,
2101                                           &core_connect_request_cont, ctx);
2102   }
2103   ctx->timeout_task =
2104       GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2105                                     &notify_connect_result, ctx);
2106 }
2107
2108 /**
2109  * Iterator for currently known peers, to ensure
2110  * that we don't try to send duplicate connect
2111  * requests to core.
2112  *
2113  * @param cls our "struct GNUNET_TESTING_ConnectContext"
2114  * @param peer identity of the peer that has connected,
2115  *        NULL when iteration has finished
2116  * @param atsi performance information
2117  *
2118  */
2119 static void
2120 core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer,
2121                         const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2122 {
2123   struct GNUNET_TESTING_ConnectContext *ctx = cls;
2124
2125   if ((peer != NULL) &&
2126       (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))))
2127   {
2128     ctx->connected = GNUNET_YES;
2129     ctx->distance = 0;          /* FIXME: distance */
2130     return;
2131   }
2132   if (peer != NULL)
2133     return; /* ignore other peers */
2134   /* peer == NULL: End of iteration over peers */
2135   
2136     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task);
2137     if (ctx->connected == GNUNET_YES)
2138     {
2139       ctx->timeout_task =
2140           GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2141       return;
2142     }
2143
2144     /* Peer not already connected, need to schedule connect request! */
2145     if (ctx->d1core == NULL)
2146     {
2147 #if DEBUG_TESTING
2148       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2149                   "Peers are NOT connected, connecting to core!\n");
2150 #endif
2151       ctx->d1core =
2152           GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify,
2153                                &connect_notify, NULL, NULL, NULL, GNUNET_NO,
2154                                NULL, GNUNET_NO, no_handlers);
2155     }
2156
2157     if (ctx->d1core == NULL)
2158     {
2159       ctx->timeout_task =
2160           GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2161       return;
2162     }
2163
2164     if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL))      /* Do not yet have the second peer's hello, set up a task to get it */
2165     {
2166       ctx->d2->th =
2167           GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL,
2168                                     NULL, NULL);
2169       if (ctx->d2->th == NULL)
2170       {
2171         GNUNET_CORE_disconnect (ctx->d1core);
2172         ctx->d1core = NULL;
2173         ctx->timeout_task =
2174           GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2175         return;
2176       }
2177       ctx->d2->ghh =
2178           GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2179     }
2180
2181     if (ctx->send_hello == GNUNET_YES)
2182     {
2183       ctx->d1th =
2184           GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL,
2185                                     NULL, NULL);
2186       if (ctx->d1th == NULL)
2187       {
2188         GNUNET_CORE_disconnect (ctx->d1core);
2189         ctx->d1core = NULL;
2190         ctx->timeout_task =
2191           GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2192         return;
2193       }
2194       GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task);
2195       ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2196     }
2197
2198     ctx->timeout_task =
2199         GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2200                                       &notify_connect_result, ctx);
2201
2202 }
2203
2204
2205 /**
2206  * Establish a connection between two GNUnet daemons.  The daemons
2207  * must both be running and not be stopped until either the
2208  * 'cb' callback is called OR the connection request has been
2209  * explicitly cancelled.
2210  *
2211  * @param d1 handle for the first daemon
2212  * @param d2 handle for the second daemon
2213  * @param timeout how long is the connection attempt
2214  *        allowed to take?
2215  * @param max_connect_attempts how many times should we try to reconnect
2216  *        (within timeout)
2217  * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume
2218  *                   the HELLO has already been exchanged
2219  * @param cb function to call at the end
2220  * @param cb_cls closure for cb
2221  * @return handle to cancel the request
2222  */
2223 struct GNUNET_TESTING_ConnectContext *
2224 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
2225                                 struct GNUNET_TESTING_Daemon *d2,
2226                                 struct GNUNET_TIME_Relative timeout,
2227                                 unsigned int max_connect_attempts,
2228                                 int send_hello,
2229                                 GNUNET_TESTING_NotifyConnection cb,
2230                                 void *cb_cls)
2231 {
2232   struct GNUNET_TESTING_ConnectContext *ctx;
2233
2234   if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
2235   {
2236     if (NULL != cb)
2237       cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2,
2238           _("Peers are not fully running yet, can not connect!\n"));
2239     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n");
2240     return NULL;
2241   }
2242
2243   ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext));
2244   ctx->d1 = d1;
2245   ctx->d2 = d2;
2246   ctx->timeout_hello =
2247       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
2248   ctx->relative_timeout =
2249       GNUNET_TIME_relative_divide (timeout, max_connect_attempts);
2250   ctx->cb = cb;
2251   ctx->cb_cls = cb_cls;
2252   ctx->connect_attempts = max_connect_attempts;
2253   ctx->connected = GNUNET_NO;
2254   ctx->send_hello = send_hello;
2255 #if DEBUG_TESTING
2256   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n",
2257               d1->shortname, d2->shortname);
2258 #endif
2259
2260   /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */
2261   GNUNET_assert (GNUNET_OK ==
2262                  GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id,
2263                                                 &core_initial_iteration, ctx));
2264   return ctx;
2265 }
2266
2267
2268 /**
2269  * Cancel an attempt to connect two daemons.
2270  *
2271  * @param cc connect context
2272  */
2273 void
2274 GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext
2275                                        *cc)
2276 {
2277   if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task)
2278     {
2279       GNUNET_SCHEDULER_cancel (cc->timeout_task);
2280       cc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2281     }
2282   if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task)
2283     {
2284       GNUNET_SCHEDULER_cancel (cc->hello_send_task);
2285       cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
2286     }
2287   if (NULL != cc->d1core)
2288     {
2289       GNUNET_CORE_disconnect (cc->d1core);
2290       cc->d1core = NULL;
2291     }
2292   if (NULL != cc->d1th)
2293     {
2294       GNUNET_TRANSPORT_disconnect (cc->d1th);
2295       cc->d1th = NULL;
2296     }
2297   GNUNET_free (cc);
2298 }
2299
2300
2301 /* end of testing.c */