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