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