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