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