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