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