5eaa0a12b09a43b38411acc1712fc29b3a23fdcb
[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 delete_files GNUNET_YES to remove files, GNUNET_NO
1550  *        to leave them
1551  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1552  *        GNUNET_NO to kill off and clean up for good
1553  */
1554 void
1555 GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d,
1556                                     char *service,
1557                                     struct GNUNET_TIME_Relative timeout,
1558                                     GNUNET_TESTING_NotifyCompletion cb,
1559                                     void *cb_cls)
1560 {
1561   char *arg;
1562
1563   d->dead_cb = cb;
1564   d->dead_cb_cls = cb_cls;
1565
1566   GNUNET_assert (d->running == GNUNET_YES);
1567
1568   if (d->phase == SP_CONFIG_UPDATE)
1569   {
1570     GNUNET_SCHEDULER_cancel (d->task);
1571     d->phase = SP_START_DONE;
1572   }
1573
1574 #if DEBUG_TESTING
1575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"),
1576               GNUNET_i2s (&d->id));
1577 #endif
1578   if (d->churned_services != NULL)
1579   {
1580     d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!");
1581     return;
1582   }
1583   d->phase = SP_SERVICE_SHUTDOWN_START;
1584   d->churned_services = GNUNET_strdup (service);
1585   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1586   /* Check if this is a local or remote process */
1587   if (NULL != d->hostname)
1588   {
1589 #if DEBUG_TESTING
1590     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591                 "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1592                 d->cfgfile, d->hostname);
1593 #endif
1594
1595     if (d->username != NULL)
1596       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1597     else
1598       arg = GNUNET_strdup (d->hostname);
1599
1600     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1601 #if !DEBUG_TESTING
1602                                        "-q",
1603 #endif
1604                                        arg, "gnunet-arm",
1605 #if DEBUG_TESTING
1606                                        "-L", "DEBUG",
1607 #endif
1608                                        "-c", d->cfgfile, "-k", service, "-q",
1609                                        "-T",
1610                                        GNUNET_TIME_relative_to_string (timeout),
1611                                        NULL);
1612     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1613                 "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n",
1614                 arg, "gnunet-arm", d->cfgfile, service);
1615     GNUNET_free (arg);
1616   }
1617   else
1618   {
1619 #if DEBUG_TESTING
1620     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621                 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
1622 #endif
1623     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1624 #if DEBUG_TESTING
1625                                        "-L", "DEBUG",
1626 #endif
1627                                        "-c", d->cfgfile, "-k", service, "-q",
1628                                        "-T",
1629                                        GNUNET_TIME_relative_to_string (timeout),
1630                                        NULL);
1631   }
1632
1633   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1634   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1635 }
1636
1637
1638 /**
1639  * Stops a GNUnet daemon.
1640  *
1641  * @param d the daemon that should be stopped
1642  * @param timeout how long to wait for process for shutdown to complete
1643  * @param cb function called once the daemon was stopped
1644  * @param cb_cls closure for cb
1645  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1646  *        to leave them
1647  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1648  *        GNUNET_NO to kill off and clean up for good
1649  */
1650 void
1651 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
1652                             struct GNUNET_TIME_Relative timeout,
1653                             GNUNET_TESTING_NotifyCompletion cb, void *cb_cls,
1654                             int delete_files, int allow_restart)
1655 {
1656   char *arg;
1657   char *del_arg;
1658
1659   d->dead_cb = cb;
1660   d->dead_cb_cls = cb_cls;
1661
1662   if (NULL != d->cb)
1663   {
1664 #if DEBUG_TESTING
1665     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"),
1666                 GNUNET_i2s (&d->id));
1667 #endif
1668     d->dead = GNUNET_YES;
1669     return;
1670   }
1671
1672   if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES))    /* Peer has already been stopped in churn context! */
1673   {
1674     /* Free what was left from churning! */
1675     GNUNET_assert (d->cfg != NULL);
1676     GNUNET_CONFIGURATION_destroy (d->cfg);
1677     if (delete_files == GNUNET_YES)
1678     {
1679       if (0 != UNLINK (d->cfgfile))
1680       {
1681         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink");
1682       }
1683     }
1684     GNUNET_free (d->cfgfile);
1685     GNUNET_free_non_null (d->hostname);
1686     GNUNET_free_non_null (d->username);
1687     if (NULL != d->dead_cb)
1688       d->dead_cb (d->dead_cb_cls, NULL);
1689     GNUNET_free (d);
1690     return;
1691   }
1692
1693   del_arg = NULL;
1694   if (delete_files == GNUNET_YES)
1695   {
1696     GNUNET_asprintf (&del_arg, "-d");
1697   }
1698
1699   if (d->phase == SP_CONFIG_UPDATE)
1700   {
1701     GNUNET_SCHEDULER_cancel (d->task);
1702     d->phase = SP_START_DONE;
1703   }
1704   /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop?
1705   if (d->server != NULL)
1706     {
1707       GNUNET_CORE_disconnect (d->server);
1708       d->server = NULL;
1709     }
1710     */
1711   /* shutdown ARM process (will terminate others) */
1712 #if DEBUG_TESTING
1713   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"),
1714               GNUNET_i2s (&d->id));
1715 #endif
1716   d->phase = SP_SHUTDOWN_START;
1717   d->running = GNUNET_NO;
1718   if (allow_restart == GNUNET_YES)
1719     d->churn = GNUNET_YES;
1720   if (d->th != NULL)
1721   {
1722     GNUNET_TRANSPORT_get_hello_cancel (d->ghh);
1723     d->ghh = NULL;
1724     GNUNET_TRANSPORT_disconnect (d->th);
1725     d->th = NULL;
1726   }
1727   /* Check if this is a local or remote process */
1728   if (NULL != d->hostname)
1729   {
1730 #if DEBUG_TESTING
1731     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732                 "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1733                 d->cfgfile, d->hostname);
1734 #endif
1735
1736     if (d->username != NULL)
1737       GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1738     else
1739       arg = GNUNET_strdup (d->hostname);
1740
1741     d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1742 #if !DEBUG_TESTING
1743                                        "-q",
1744 #endif
1745                                        arg, "gnunet-arm",
1746 #if DEBUG_TESTING
1747                                        "-L", "DEBUG",
1748 #endif
1749                                        "-c", d->cfgfile, "-e", "-q", "-T",
1750                                        GNUNET_TIME_relative_to_string (timeout),
1751                                        del_arg, NULL);
1752     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753                 "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n",
1754                 arg, "gnunet-arm", d->cfgfile, del_arg);
1755     /* Use -e to end arm, and -d to remove temp files */
1756     GNUNET_free (arg);
1757   }
1758   else
1759   {
1760 #if DEBUG_TESTING
1761     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1762                 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
1763 #endif
1764     d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm", "gnunet-arm",
1765 #if DEBUG_TESTING
1766                                        "-L", "DEBUG",
1767 #endif
1768                                        "-c", d->cfgfile, "-e", "-q", "-T",
1769                                        GNUNET_TIME_relative_to_string (timeout),
1770                                        del_arg, NULL);
1771   }
1772
1773   GNUNET_free_non_null (del_arg);
1774   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1775   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1776 }
1777
1778
1779 /**
1780  * Changes the configuration of a GNUnet daemon.
1781  *
1782  * @param d the daemon that should be modified
1783  * @param cfg the new configuration for the daemon
1784  * @param cb function called once the configuration was changed
1785  * @param cb_cls closure for cb
1786  */
1787 void
1788 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
1789                                    struct GNUNET_CONFIGURATION_Handle *cfg,
1790                                    GNUNET_TESTING_NotifyCompletion cb,
1791                                    void *cb_cls)
1792 {
1793   char *arg;
1794
1795   if (d->phase != SP_START_DONE)
1796   {
1797     if (NULL != cb)
1798       cb (cb_cls,
1799           _
1800           ("Peer not yet running, can not change configuration at this point."));
1801     return;
1802   }
1803
1804   /* 1) write configuration to temporary file */
1805   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
1806   {
1807     if (NULL != cb)
1808       cb (cb_cls, _("Failed to write new configuration to disk."));
1809     return;
1810   }
1811
1812   /* 2) copy file to remote host (if necessary) */
1813   if (NULL == d->hostname)
1814   {
1815     /* signal success */
1816     if (NULL != cb)
1817       cb (cb_cls, NULL);
1818     return;
1819   }
1820 #if DEBUG_TESTING
1821   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1822               "Copying updated configuration file to remote host `%s'.\n",
1823               d->hostname);
1824 #endif
1825   d->phase = SP_CONFIG_UPDATE;
1826   if (NULL != d->username)
1827     GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
1828   else
1829     GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
1830   d->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
1831 #if !DEBUG_TESTING
1832                                      "-q",
1833 #endif
1834                                      d->cfgfile, arg, NULL);
1835   GNUNET_free (arg);
1836   if (NULL == d->proc)
1837   {
1838     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1839                 _("Could not start `%s' process to copy configuration file.\n"),
1840                 "scp");
1841     if (NULL != cb)
1842       cb (cb_cls, _("Failed to copy new configuration to remote machine."));
1843     d->phase = SP_START_DONE;
1844     return;
1845   }
1846   d->update_cb = cb;
1847   d->update_cb_cls = cb_cls;
1848   d->task =
1849       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d);
1850 }
1851
1852
1853 /**
1854  * Data kept for each pair of peers that we try
1855  * to connect.
1856  */
1857 struct ConnectContext
1858 {
1859   /**
1860    * Testing handle to the first daemon.
1861    */
1862   struct GNUNET_TESTING_Daemon *d1;
1863
1864   /**
1865    * Handle to core of first daemon (to check connect)
1866    */
1867   struct GNUNET_CORE_Handle *d1core;
1868
1869   /**
1870    * Have we actually connected to the core of the first daemon yet?
1871    */
1872   int d1core_ready;
1873
1874   /**
1875    * Testing handle to the second daemon.
1876    */
1877   struct GNUNET_TESTING_Daemon *d2;
1878
1879   /**
1880    * Handler for the request to core to connect to this peer.
1881    */
1882   struct GNUNET_CORE_PeerRequestHandle *connect_request_handle;
1883
1884   /**
1885    * Transport handle to the first daemon (to offer the HELLO of the second daemon to).
1886    */
1887   struct GNUNET_TRANSPORT_Handle *d1th;
1888
1889   /**
1890    * Function to call once we are done (or have timed out).
1891    */
1892   GNUNET_TESTING_NotifyConnection cb;
1893
1894   /**
1895    * Closure for "nb".
1896    */
1897   void *cb_cls;
1898
1899   /**
1900    * The relative timeout from whence this connect attempt was
1901    * started.  Allows for reconnect attempts.
1902    */
1903   struct GNUNET_TIME_Relative relative_timeout;
1904
1905   /**
1906    * Maximum number of connect attempts, will retry connection
1907    * this number of times on failures.
1908    */
1909   unsigned int connect_attempts;
1910
1911   /**
1912    * Hello timeout task
1913    */
1914   GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
1915
1916   /**
1917    * Connect timeout task
1918    */
1919   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1920
1921   /**
1922    * When should this operation be complete (or we must trigger
1923    * a timeout).
1924    */
1925   struct GNUNET_TIME_Relative timeout_hello;
1926
1927   /**
1928    * Was the connection attempt successful?
1929    */
1930   int connected;
1931
1932   /**
1933    * When connecting, do we need to send the HELLO?
1934    */
1935   int send_hello;
1936
1937   /**
1938    * The distance between the two connected peers
1939    */
1940   uint32_t distance;
1941 };
1942
1943
1944 /** Forward declaration **/
1945 static void
1946 reattempt_daemons_connect (void *cls,
1947                            const struct GNUNET_SCHEDULER_TaskContext *tc);
1948
1949
1950 /**
1951  * Notify callback about success or failure of the attempt
1952  * to connect the two peers
1953  *
1954  * @param cls our "struct ConnectContext" (freed)
1955  * @param tc reason tells us if we succeeded or failed
1956  */
1957 static void
1958 notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1959 {
1960   struct ConnectContext *ctx = cls;
1961
1962   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1963   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1964   {
1965     GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1966     ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1967   }
1968
1969   if (ctx->connect_request_handle != NULL)
1970   {
1971     GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle);
1972     ctx->connect_request_handle = NULL;
1973   }
1974
1975   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1976   {
1977     if (ctx->d1th != NULL)
1978       GNUNET_TRANSPORT_disconnect (ctx->d1th);
1979     ctx->d1th = NULL;
1980     if (ctx->d1core != NULL)
1981       GNUNET_CORE_disconnect (ctx->d1core);
1982 #if CONNECT_CORE2
1983     if (ctx->d2core != NULL)
1984       GNUNET_CORE_disconnect (ctx->d2core);
1985     ctx->d2core = NULL;
1986 #endif
1987     ctx->d1core = NULL;
1988     GNUNET_free (ctx);
1989     return;
1990   }
1991
1992   if (ctx->d1th != NULL)
1993     GNUNET_TRANSPORT_disconnect (ctx->d1th);
1994   ctx->d1th = NULL;
1995   if (ctx->d1core != NULL)
1996     GNUNET_CORE_disconnect (ctx->d1core);
1997   ctx->d1core = NULL;
1998
1999   if (ctx->connected == GNUNET_YES)
2000   {
2001     if (ctx->cb != NULL)
2002     {
2003       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance,
2004                ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
2005     }
2006   }
2007   else if (ctx->connect_attempts > 0)
2008   {
2009     ctx->d1core_ready = GNUNET_NO;
2010 #if CONNECT_CORE2
2011     if (ctx->d2core != NULL)
2012     {
2013       GNUNET_CORE_disconnect (ctx->d2core);
2014       ctx->d2core = NULL;
2015     }
2016 #endif
2017     GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx);
2018     return;
2019   }
2020   else
2021   {
2022     if (ctx->cb != NULL)
2023     {
2024       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2025                ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect"));
2026     }
2027   }
2028
2029   GNUNET_free (ctx);
2030 }
2031
2032
2033 /**
2034  * Success, connection is up.  Signal client our success.
2035  *
2036  * @param cls our "struct ConnectContext"
2037  * @param peer identity of the peer that has connected
2038  * @param atsi performance information
2039  *
2040  */
2041 static void
2042 connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer,
2043                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2044 {
2045   struct ConnectContext *ctx = cls;
2046
2047 #if DEBUG_TESTING
2048   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Connected peer %s to peer %s\n",
2049               ctx->d1->shortname, GNUNET_i2s (peer));
2050 #endif
2051
2052   if (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))
2053   {
2054
2055     ctx->connected = GNUNET_YES;
2056     ctx->distance = 0;          /* FIXME: distance */
2057     if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
2058     {
2059       GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
2060       ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
2061     }
2062     GNUNET_SCHEDULER_cancel (ctx->timeout_task);
2063     ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2064   }
2065 }
2066
2067 #if CONNECT_CORE2
2068 /**
2069  * Success, connection is up.  Signal client our success.
2070  *
2071  * @param cls our "struct ConnectContext"
2072  * @param peer identity of the peer that has connected
2073  * @param atsi performance information
2074  *
2075  */
2076 static void
2077 connect_notify_core2 (void *cls, const struct GNUNET_PeerIdentity *peer,
2078                       const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2079 {
2080   struct ConnectContext *ctx = cls;
2081
2082   if (memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
2083   {
2084     ctx->connected = GNUNET_YES;
2085     ctx->distance = 0;          /* FIXME: distance */
2086     GNUNET_SCHEDULER_cancel (ctx->timeout_task);
2087     ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2088   }
2089
2090 }
2091 #endif
2092
2093 /**
2094  * Task called once a core connect request has been transmitted.
2095  *
2096  * @param cls struct ConnectContext
2097  * @param success was the request successful?
2098  */
2099 void
2100 core_connect_request_cont (void *cls, int success)
2101 {
2102   struct ConnectContext *ctx = cls;
2103
2104   ctx->connect_request_handle = NULL;
2105 }
2106
2107 static void
2108 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2109 {
2110   struct ConnectContext *ctx = cls;
2111   struct GNUNET_MessageHeader *hello;
2112
2113   ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
2114   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2115     return;
2116   if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) &&
2117       (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) &&
2118       (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE))
2119   {
2120     hello = GNUNET_HELLO_get_header (ctx->d2->hello);
2121     GNUNET_assert (hello != NULL);
2122 #if DEBUG_TESTING
2123     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n",
2124                 ctx->d2->shortname, ctx->d1->shortname);
2125 #endif
2126     GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL);
2127     GNUNET_assert (ctx->d1core != NULL);
2128     ctx->connect_request_handle =
2129         GNUNET_CORE_peer_request_connect (ctx->d1core, &ctx->d2->id,
2130                                           &core_connect_request_cont, ctx);
2131
2132 #if DEBUG_TESTING
2133     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2134                 "Sending connect request to CORE of %s for peer %s\n",
2135                 GNUNET_i2s (&ctx->d1->id),
2136                 GNUNET_h2s (&ctx->d2->id.hashPubKey));
2137 #endif
2138     ctx->timeout_hello =
2139         GNUNET_TIME_relative_add (ctx->timeout_hello,
2140                                   GNUNET_TIME_relative_multiply
2141                                   (GNUNET_TIME_UNIT_MILLISECONDS, 500));
2142   }
2143   ctx->hello_send_task =
2144       GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx);
2145 }
2146
2147 /**
2148  * Notify of a successful connection to the core service.
2149  *
2150  * @param cls a ConnectContext
2151  * @param server handle to the core service
2152  * @param my_identity the peer identity of this peer
2153  * @param publicKey the public key of the peer
2154  */
2155 void
2156 core_init_notify (void *cls, struct GNUNET_CORE_Handle *server,
2157                   const struct GNUNET_PeerIdentity *my_identity,
2158                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
2159                   *publicKey)
2160 {
2161   struct ConnectContext *connect_ctx = cls;
2162
2163   connect_ctx->d1core_ready = GNUNET_YES;
2164
2165   if (connect_ctx->send_hello == GNUNET_NO)
2166   {
2167     connect_ctx->connect_request_handle =
2168         GNUNET_CORE_peer_request_connect (connect_ctx->d1core,
2169                                           &connect_ctx->d2->id,
2170                                           &core_connect_request_cont,
2171                                           connect_ctx);
2172     GNUNET_assert (connect_ctx->connect_request_handle != NULL);
2173 #if DEBUG_TESTING
2174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2175                 "Sending connect request to CORE of %s for peer %s\n",
2176                 connect_ctx->d1->shortname, connect_ctx->d2->shortname);
2177 #endif
2178   }
2179
2180 }
2181
2182
2183 static void
2184 reattempt_daemons_connect (void *cls,
2185                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2186 {
2187   struct ConnectContext *ctx = cls;
2188
2189   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2190   {
2191     GNUNET_free (ctx);
2192     return;
2193   }
2194 #if DEBUG_TESTING_RECONNECT
2195   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2196               "re-attempting connect of peer %s to peer %s\n",
2197               ctx->d1->shortname, ctx->d2->shortname);
2198 #endif
2199   ctx->connect_attempts--;
2200   GNUNET_assert (ctx->d1core == NULL);
2201   ctx->d1core_ready = GNUNET_NO;
2202   ctx->d1core =
2203       GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify,
2204                            &connect_notify, NULL, NULL, NULL, GNUNET_NO, NULL,
2205                            GNUNET_NO, no_handlers);
2206   if (ctx->d1core == NULL)
2207   {
2208     if (NULL != ctx->cb)
2209       ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2210                ctx->d2->cfg, ctx->d1, ctx->d2,
2211                _("Failed to connect to core service of first peer!\n"));
2212     GNUNET_free (ctx);
2213     return;
2214   }
2215
2216   /* Don't know reason for initial connect failure, update the HELLO for the second peer */
2217   if (NULL != ctx->d2->hello)
2218   {
2219     GNUNET_free (ctx->d2->hello);
2220     ctx->d2->hello = NULL;
2221     if (NULL != ctx->d2->th)
2222     {
2223       GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh);
2224       ctx->d2->ghh = NULL;
2225       GNUNET_TRANSPORT_disconnect (ctx->d2->th);
2226     }
2227     ctx->d2->th =
2228         GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL,
2229                                   NULL);
2230     GNUNET_assert (ctx->d2->th != NULL);
2231     ctx->d2->ghh =
2232         GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2233   }
2234
2235   if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL))
2236   {
2237     ctx->d2->th =
2238         GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL,
2239                                   NULL);
2240     if (ctx->d2->th == NULL)
2241     {
2242       GNUNET_CORE_disconnect (ctx->d1core);
2243       GNUNET_free (ctx);
2244       if (NULL != ctx->cb)
2245         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2246                  ctx->d2->cfg, ctx->d1, ctx->d2,
2247                  _("Failed to connect to transport service!\n"));
2248       return;
2249     }
2250     ctx->d2->ghh =
2251         GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2252   }
2253
2254   if (ctx->send_hello == GNUNET_YES)
2255   {
2256     ctx->d1th =
2257         GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL,
2258                                   NULL, NULL);
2259     if (ctx->d1th == NULL)
2260     {
2261       GNUNET_CORE_disconnect (ctx->d1core);
2262       GNUNET_free (ctx);
2263       if (NULL != ctx->cb)
2264         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2265                  ctx->d2->cfg, ctx->d1, ctx->d2,
2266                  _("Failed to connect to transport service!\n"));
2267       return;
2268     }
2269     ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2270   }
2271   else
2272   {
2273     ctx->connect_request_handle =
2274         GNUNET_CORE_peer_request_connect (ctx->d1core, &ctx->d2->id,
2275                                           &core_connect_request_cont, ctx);
2276   }
2277   ctx->timeout_task =
2278       GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2279                                     &notify_connect_result, ctx);
2280 }
2281
2282 /**
2283  * Iterator for currently known peers, to ensure
2284  * that we don't try to send duplicate connect
2285  * requests to core.
2286  *
2287  * @param cls our "struct ConnectContext"
2288  * @param peer identity of the peer that has connected,
2289  *        NULL when iteration has finished
2290  * @param atsi performance information
2291  *
2292  */
2293 static void
2294 core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer,
2295                         const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2296 {
2297   struct ConnectContext *ctx = cls;
2298
2299   if ((peer != NULL) &&
2300       (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))))
2301   {
2302     ctx->connected = GNUNET_YES;
2303     ctx->distance = 0;          /* FIXME: distance */
2304     return;
2305   }
2306   else if (peer == NULL)        /* End of iteration over peers */
2307   {
2308     if (ctx->connected == GNUNET_YES)
2309     {
2310       ctx->timeout_task =
2311           GNUNET_SCHEDULER_add_now (&notify_connect_result, ctx);
2312       return;
2313     }
2314
2315     /* Peer not already connected, need to schedule connect request! */
2316     if (ctx->d1core == NULL)
2317     {
2318 #if DEBUG_TESTING
2319       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2320                   "Peers are NOT connected, connecting to core!\n");
2321 #endif
2322       ctx->d1core =
2323           GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify,
2324                                &connect_notify, NULL, NULL, NULL, GNUNET_NO,
2325                                NULL, GNUNET_NO, no_handlers);
2326     }
2327
2328     if (ctx->d1core == NULL)
2329     {
2330       GNUNET_free (ctx);
2331       if (NULL != ctx->cb)
2332         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2333                  ctx->d2->cfg, ctx->d1, ctx->d2,
2334                  _("Failed to connect to core service of first peer!\n"));
2335       return;
2336     }
2337
2338     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 */
2339     {
2340       ctx->d2->th =
2341           GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL,
2342                                     NULL, NULL);
2343       if (ctx->d2->th == NULL)
2344       {
2345         GNUNET_CORE_disconnect (ctx->d1core);
2346         GNUNET_free (ctx);
2347         if (NULL != ctx->cb)
2348           ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2349                    ctx->d2->cfg, ctx->d1, ctx->d2,
2350                    _("Failed to connect to transport service!\n"));
2351         return;
2352       }
2353       ctx->d2->ghh =
2354           GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2355     }
2356
2357     if (ctx->send_hello == GNUNET_YES)
2358     {
2359       ctx->d1th =
2360           GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL,
2361                                     NULL, NULL);
2362       if (ctx->d1th == NULL)
2363       {
2364         GNUNET_CORE_disconnect (ctx->d1core);
2365         GNUNET_free (ctx);
2366         if (NULL != ctx->cb)
2367           ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2368                    ctx->d2->cfg, ctx->d1, ctx->d2,
2369                    _("Failed to connect to transport service!\n"));
2370         return;
2371       }
2372       ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2373     }
2374
2375     ctx->timeout_task =
2376         GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2377                                       &notify_connect_result, ctx);
2378   }
2379 }
2380
2381
2382 /**
2383  * Establish a connection between two GNUnet daemons.
2384  *
2385  * @param d1 handle for the first daemon
2386  * @param d2 handle for the second daemon
2387  * @param timeout how long is the connection attempt
2388  *        allowed to take?
2389  * @param max_connect_attempts how many times should we try to reconnect
2390  *        (within timeout)
2391  * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume
2392  *                   the HELLO has already been exchanged
2393  * @param cb function to call at the end
2394  * @param cb_cls closure for cb
2395  */
2396 void
2397 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
2398                                 struct GNUNET_TESTING_Daemon *d2,
2399                                 struct GNUNET_TIME_Relative timeout,
2400                                 unsigned int max_connect_attempts,
2401                                 int send_hello,
2402                                 GNUNET_TESTING_NotifyConnection cb,
2403                                 void *cb_cls)
2404 {
2405   struct ConnectContext *ctx;
2406
2407   if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
2408   {
2409     if (NULL != cb)
2410       cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2,
2411           _("Peers are not fully running yet, can not connect!\n"));
2412     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n");
2413     return;
2414   }
2415
2416   ctx = GNUNET_malloc (sizeof (struct ConnectContext));
2417   ctx->d1 = d1;
2418   ctx->d2 = d2;
2419   ctx->timeout_hello =
2420       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
2421   ctx->relative_timeout =
2422       GNUNET_TIME_relative_divide (timeout, max_connect_attempts);
2423   ctx->cb = cb;
2424   ctx->cb_cls = cb_cls;
2425   ctx->connect_attempts = max_connect_attempts;
2426   ctx->connected = GNUNET_NO;
2427   ctx->send_hello = send_hello;
2428 #if DEBUG_TESTING
2429   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n",
2430               d1->shortname, d2->shortname);
2431 #endif
2432
2433   /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */
2434   GNUNET_assert (GNUNET_OK ==
2435                  GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id,
2436                                                 &core_initial_iteration, ctx));
2437   /*GNUNET_assert(GNUNET_OK == GNUNET_CORE_iterate_peers (ctx->d1->cfg, &core_initial_iteration, ctx)); */
2438 }
2439
2440 /* end of testing.c */