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