remove core connect call, add core to defaultservices for test case
[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);
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:
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 hostname name of the machine where to run GNUnet
954  *        (use NULL for localhost).
955  * @param ssh_username ssh username to use when connecting to hostname
956  * @param sshport port to pass to ssh process when connecting to hostname
957  * @param hostkey pointer to a hostkey to be written to disk (instead of being generated)
958  * @param hostkey_callback function to call once the hostkey has been
959  *        generated for this peer, but it hasn't yet been started
960  *        (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start)
961  * @param hostkey_cls closure for hostkey callback
962  * @param cb function to call once peer is up, or failed to start
963  * @param cb_cls closure for cb
964  * @return handle to the daemon (actual start will be completed asynchronously)
965  */
966 struct GNUNET_TESTING_Daemon *
967 GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
968                              struct GNUNET_TIME_Relative timeout,
969                              const char *hostname,
970                              const char *ssh_username,
971                              uint16_t sshport,
972                              const char *hostkey,
973                              GNUNET_TESTING_NotifyHostkeyCreated
974                              hostkey_callback, void *hostkey_cls,
975                              GNUNET_TESTING_NotifyDaemonRunning cb,
976                              void *cb_cls)
977 {
978   struct GNUNET_TESTING_Daemon *ret;
979   char *arg;
980   char *username;
981   char *servicehome;
982   char *baseservicehome;
983   char *slash;
984   char *hostkeyfile;
985   char *temp_file_name;
986   struct GNUNET_DISK_FileHandle *fn;
987   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
988   struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
989
990   ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon));
991   ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
992   if (sshport != 0)
993     {
994       GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport);
995     }
996   else
997     ret->ssh_port_str = NULL;
998
999   /* Find service home and base service home directories, create it if it doesn't exist */
1000   GNUNET_assert(GNUNET_OK ==
1001                 GNUNET_CONFIGURATION_get_value_string (cfg,
1002                                                        "PATHS",
1003                                                        "SERVICEHOME",
1004                                                        &servicehome));
1005
1006   GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome));
1007   GNUNET_asprintf(&temp_file_name, "%s/gnunet-testing-config", servicehome);
1008   ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name);
1009   GNUNET_free(temp_file_name);
1010 #if DEBUG_TESTING
1011   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012               "Setting up peer with configuration file `%s'.\n",
1013               ret->cfgfile);
1014 #endif
1015   if (NULL == ret->cfgfile)
1016     {
1017       GNUNET_free_non_null (ret->ssh_port_str);
1018       GNUNET_free_non_null (ret->hostname);
1019       GNUNET_free (ret);
1020       return NULL;
1021     }
1022   ret->hostkey_callback = hostkey_callback;
1023   ret->hostkey_cls = hostkey_cls;
1024   ret->cb = cb;
1025   ret->cb_cls = cb_cls;
1026   ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1027   ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
1028   GNUNET_CONFIGURATION_set_value_string (ret->cfg,
1029                                          "PATHS",
1030                                          "DEFAULTCONFIG", ret->cfgfile);
1031
1032   if (hostkey != NULL) /* Get the peer identity from the hostkey */
1033     {
1034       private_key = GNUNET_CRYPTO_rsa_decode_key(hostkey, HOSTKEYFILESIZE);
1035       GNUNET_assert(private_key != NULL);
1036       GNUNET_CRYPTO_rsa_key_get_public (private_key,
1037                                         &public_key);
1038       GNUNET_CRYPTO_hash(&public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &ret->id.hashPubKey);
1039       ret->shortname = GNUNET_strdup(GNUNET_i2s(&ret->id));
1040       ret->have_hostkey = GNUNET_YES;
1041       GNUNET_CRYPTO_rsa_key_free(private_key);
1042     }
1043
1044   /* Write hostkey to file, if we were given one */
1045   hostkeyfile = NULL;
1046   if (hostkey != NULL)
1047     {
1048       GNUNET_asprintf(&hostkeyfile, "%s/.hostkey", servicehome);
1049       fn =
1050       GNUNET_DISK_file_open (hostkeyfile,
1051                              GNUNET_DISK_OPEN_READWRITE
1052                              | GNUNET_DISK_OPEN_CREATE,
1053                              GNUNET_DISK_PERM_USER_READ |
1054                              GNUNET_DISK_PERM_USER_WRITE);
1055       GNUNET_assert(fn != NULL);
1056       GNUNET_assert(HOSTKEYFILESIZE == GNUNET_DISK_file_write(fn, hostkey, HOSTKEYFILESIZE));
1057       GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fn));
1058     }
1059
1060   /* write configuration to temporary file */
1061   if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile))
1062     {
1063       if (0 != UNLINK (ret->cfgfile))
1064         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1065                                   "unlink", ret->cfgfile);
1066       GNUNET_CONFIGURATION_destroy (ret->cfg);
1067       GNUNET_free_non_null (ret->hostname);
1068       GNUNET_free (ret->cfgfile);
1069       GNUNET_free (ret);
1070       return NULL;
1071     }
1072   if (ssh_username != NULL)
1073     username = GNUNET_strdup (ssh_username);
1074   if ((ssh_username == NULL) && (GNUNET_OK !=
1075                                  GNUNET_CONFIGURATION_get_value_string (cfg,
1076                                                                         "TESTING",
1077                                                                         "USERNAME",
1078                                                                         &username)))
1079     {
1080       if (NULL != getenv ("USER"))
1081         username = GNUNET_strdup (getenv ("USER"));
1082       else
1083         username = NULL;
1084     }
1085   ret->username = username;
1086
1087   /* copy directory to remote host */
1088   if (NULL != hostname)
1089     {
1090 #if DEBUG_TESTING
1091       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092                   "Copying configuration directory to host `%s'.\n", hostname);
1093 #endif
1094       baseservicehome = GNUNET_strdup(servicehome);
1095       /* Remove trailing /'s */
1096       while (baseservicehome[strlen(baseservicehome) - 1] == '/')
1097         baseservicehome[strlen(baseservicehome) - 1] = '\0';
1098       /* Find next directory /, jump one ahead */
1099       slash = strrchr(baseservicehome, '/');
1100       if (slash != NULL)
1101         *(++slash) = '\0';
1102
1103       ret->phase = SP_COPYING;
1104       if (NULL != username)
1105         GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome);
1106       else
1107         GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome);
1108
1109       if (ret->ssh_port_str == NULL)
1110         {
1111           ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp", "-r",
1112 #if !DEBUG_TESTING
1113                                                "-q",
1114 #endif
1115                                                servicehome, arg, NULL);
1116 #if DEBUG_TESTING
1117           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "copying directory with command scp -r %s %s\n", servicehome, arg);
1118 #endif
1119         }
1120       else
1121         {
1122           ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp",
1123                                                "scp", "-r", "-P", ret->ssh_port_str,
1124 #if !DEBUG_TESTING
1125                                                "-q",
1126 #endif
1127                                                servicehome, arg, NULL);
1128         }
1129       GNUNET_free (arg);
1130       if (NULL == ret->proc)
1131         {
1132           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1133                       _
1134                       ("Could not start `%s' process to copy configuration directory.\n"),
1135                       "scp");
1136           if (0 != UNLINK (ret->cfgfile))
1137             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1138                                       "unlink", ret->cfgfile);
1139           GNUNET_CONFIGURATION_destroy (ret->cfg);
1140           GNUNET_free_non_null (ret->hostname);
1141           GNUNET_free_non_null (ret->username);
1142           GNUNET_free (ret->cfgfile);
1143           GNUNET_free (ret);
1144           if ((hostkey != NULL) && (0 != UNLINK(hostkeyfile)))
1145             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1146                                       "unlink", hostkeyfile);
1147           GNUNET_free_non_null(hostkeyfile);
1148           GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome));
1149           GNUNET_free(servicehome);
1150           return NULL;
1151         }
1152
1153       ret->task
1154         = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1155                                         &start_fsm, ret);
1156       GNUNET_free_non_null(hostkeyfile);
1157       GNUNET_free(baseservicehome);
1158       GNUNET_free(servicehome);
1159       return ret;
1160     }
1161 #if DEBUG_TESTING
1162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1163               "No need to copy configuration file since we are running locally.\n");
1164 #endif
1165   ret->phase = SP_COPIED;
1166   GNUNET_SCHEDULER_add_continuation (&start_fsm,
1167                                      ret,
1168                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1169   GNUNET_free_non_null(hostkeyfile);
1170   GNUNET_free(servicehome);
1171   return ret;
1172 }
1173
1174
1175 /**
1176  * Restart (stop and start) a GNUnet daemon.
1177  *
1178  * @param d the daemon that should be restarted
1179  * @param cb function called once the daemon is (re)started
1180  * @param cb_cls closure for cb
1181  */
1182 void
1183 GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d,
1184                                GNUNET_TESTING_NotifyDaemonRunning cb,
1185                                void *cb_cls)
1186 {
1187   char *arg;
1188   char *del_arg;
1189
1190   del_arg = NULL;
1191   if (NULL != d->cb)
1192     {
1193       d->dead = GNUNET_YES;
1194       return;
1195     }
1196
1197   d->cb = cb;
1198   d->cb_cls = cb_cls;
1199
1200   if (d->phase == SP_CONFIG_UPDATE)
1201     {
1202       GNUNET_SCHEDULER_cancel (d->task);
1203       d->phase = SP_START_DONE;
1204     }
1205   if (d->server != NULL)
1206     {
1207       GNUNET_CORE_disconnect (d->server);
1208       d->server = NULL;
1209     }
1210
1211   if (d->th != NULL)
1212     {
1213       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1214       GNUNET_TRANSPORT_disconnect (d->th);
1215       d->th = NULL;
1216     }
1217   /* state clean up and notifications */
1218   GNUNET_free_non_null (d->hello);
1219
1220 #if DEBUG_TESTING
1221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1222               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1223 #endif
1224
1225   d->phase = SP_START_ARMING;
1226
1227   /* Check if this is a local or remote process */
1228   if (NULL != d->hostname)
1229     {
1230 #if DEBUG_TESTING
1231       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1232                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1233                   d->cfgfile, d->hostname);
1234 #endif
1235
1236       if (d->username != NULL)
1237         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1238       else
1239         arg = GNUNET_strdup (d->hostname);
1240
1241       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1242 #if !DEBUG_TESTING
1243                                          "-q",
1244 #endif
1245                                          arg, "gnunet-arm",
1246 #if DEBUG_TESTING
1247                                          "-L", "DEBUG",
1248 #endif
1249                                          "-c", d->cfgfile, "-e", "-r", NULL);
1250       /* Use -r to restart arm and all services */
1251
1252       GNUNET_free (arg);
1253     }
1254   else
1255     {
1256 #if DEBUG_TESTING
1257       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1258                   "Stopping gnunet-arm with config `%s' locally.\n",
1259                   d->cfgfile);
1260 #endif
1261       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1262                                          "gnunet-arm",
1263 #if DEBUG_TESTING
1264                                          "-L", "DEBUG",
1265 #endif
1266                                          "-c", d->cfgfile, "-e", "-r", NULL);
1267     }
1268
1269   GNUNET_free_non_null (del_arg);
1270   d->task
1271     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1272                                     &start_fsm, d);
1273
1274 }
1275
1276
1277 /**
1278  * Stops a GNUnet daemon.
1279  *
1280  * @param d the daemon that should be stopped
1281  * @param timeout how long to wait for process for shutdown to complete
1282  * @param cb function called once the daemon was stopped
1283  * @param cb_cls closure for cb
1284  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1285  *        to leave them
1286  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1287  *        GNUNET_NO to kill off and clean up for good
1288  */
1289 void
1290 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
1291                             struct GNUNET_TIME_Relative timeout,
1292                             GNUNET_TESTING_NotifyCompletion cb, void *cb_cls,
1293                             int delete_files, int allow_restart)
1294 {
1295   char *arg;
1296   char *del_arg;
1297   d->dead_cb = cb;
1298   d->dead_cb_cls = cb_cls;
1299
1300   if (NULL != d->cb)
1301     {
1302 #if DEBUG_TESTING
1303       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1304                   _("Setting d->dead on peer `%4s'\n"), GNUNET_i2s (&d->id));
1305 #endif
1306       d->dead = GNUNET_YES;
1307       return;
1308     }
1309
1310   if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES))    /* Peer has already been stopped in churn context! */
1311     {
1312       /* Free what was left from churning! */
1313       GNUNET_assert (d->cfg != NULL);
1314       GNUNET_CONFIGURATION_destroy (d->cfg);
1315       if (delete_files == GNUNET_YES)
1316         {
1317           if (0 != UNLINK (d->cfgfile))
1318             {
1319               GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink");
1320             }
1321         }
1322       GNUNET_free (d->cfgfile);
1323       GNUNET_free_non_null (d->hostname);
1324       GNUNET_free_non_null (d->username);
1325       if (NULL != d->dead_cb)
1326         d->dead_cb (d->dead_cb_cls, NULL);
1327       GNUNET_free (d);
1328       return;
1329     }
1330
1331   del_arg = NULL;
1332   if (delete_files == GNUNET_YES)
1333     {
1334       GNUNET_asprintf (&del_arg, "-d");
1335     }
1336
1337   if (d->phase == SP_CONFIG_UPDATE)
1338     {
1339       GNUNET_SCHEDULER_cancel (d->task);
1340       d->phase = SP_START_DONE;
1341     }
1342   /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop?
1343   if (d->server != NULL)
1344     {
1345       GNUNET_CORE_disconnect (d->server);
1346       d->server = NULL;
1347     }
1348     */
1349   /* shutdown ARM process (will terminate others) */
1350 #if DEBUG_TESTING
1351   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1352               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1353 #endif
1354   d->phase = SP_SHUTDOWN_START;
1355   d->running = GNUNET_NO;
1356   if (allow_restart == GNUNET_YES)
1357     d->churn = GNUNET_YES;
1358   if (d->th != NULL)
1359     {
1360       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1361       GNUNET_TRANSPORT_disconnect (d->th);
1362       d->th = NULL;
1363     }
1364   /* Check if this is a local or remote process */
1365   if (NULL != d->hostname)
1366     {
1367 #if DEBUG_TESTING
1368       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1369                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1370                   d->cfgfile, d->hostname);
1371 #endif
1372
1373       if (d->username != NULL)
1374         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1375       else
1376         arg = GNUNET_strdup (d->hostname);
1377
1378       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1379 #if !DEBUG_TESTING
1380                                          "-q",
1381 #endif
1382                                          arg, "gnunet-arm",
1383 #if DEBUG_TESTING
1384                                          "-L", "DEBUG",
1385 #endif
1386                                          "-c", d->cfgfile, "-e", "-q",
1387                                          del_arg, NULL);
1388       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389                   "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n",
1390                   arg, "gnunet-arm", d->cfgfile, del_arg);
1391       /* Use -e to end arm, and -d to remove temp files */
1392       GNUNET_free (arg);
1393     }
1394   else
1395     {
1396 #if DEBUG_TESTING
1397       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398                   "Stopping gnunet-arm with config `%s' locally.\n",
1399                   d->cfgfile);
1400 #endif
1401       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1402                                          "gnunet-arm",
1403 #if DEBUG_TESTING
1404                                          "-L", "DEBUG",
1405 #endif
1406                                          "-c", d->cfgfile, "-e", "-q",
1407                                          del_arg, NULL);
1408     }
1409
1410   GNUNET_free_non_null (del_arg);
1411   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1412   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1413 }
1414
1415
1416 /**
1417  * Changes the configuration of a GNUnet daemon.
1418  *
1419  * @param d the daemon that should be modified
1420  * @param cfg the new configuration for the daemon
1421  * @param cb function called once the configuration was changed
1422  * @param cb_cls closure for cb
1423  */
1424 void
1425 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
1426                                    struct GNUNET_CONFIGURATION_Handle *cfg,
1427                                    GNUNET_TESTING_NotifyCompletion cb,
1428                                    void *cb_cls)
1429 {
1430   char *arg;
1431
1432   if (d->phase != SP_START_DONE)
1433     {
1434       if (NULL != cb)
1435         cb (cb_cls,
1436             _
1437             ("Peer not yet running, can not change configuration at this point."));
1438       return;
1439     }
1440
1441   /* 1) write configuration to temporary file */
1442   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
1443     {
1444       if (NULL != cb)
1445         cb (cb_cls, _("Failed to write new configuration to disk."));
1446       return;
1447     }
1448
1449   /* 2) copy file to remote host (if necessary) */
1450   if (NULL == d->hostname)
1451     {
1452       /* signal success */
1453       if (NULL != cb)
1454         cb (cb_cls, NULL);
1455       return;
1456     }
1457 #if DEBUG_TESTING
1458   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459               "Copying updated configuration file to remote host `%s'.\n",
1460               d->hostname);
1461 #endif
1462   d->phase = SP_CONFIG_UPDATE;
1463   if (NULL != d->username)
1464     GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
1465   else
1466     GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
1467   d->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
1468 #if !DEBUG_TESTING
1469                                      "-q",
1470 #endif
1471                                      d->cfgfile, arg, NULL);
1472   GNUNET_free (arg);
1473   if (NULL == d->proc)
1474     {
1475       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1476                   _
1477                   ("Could not start `%s' process to copy configuration file.\n"),
1478                   "scp");
1479       if (NULL != cb)
1480         cb (cb_cls, _("Failed to copy new configuration to remote machine."));
1481       d->phase = SP_START_DONE;
1482       return;
1483     }
1484   d->update_cb = cb;
1485   d->update_cb_cls = cb_cls;
1486   d->task
1487     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1488                                     &start_fsm, d);
1489 }
1490
1491
1492 /**
1493  * Data kept for each pair of peers that we try
1494  * to connect.
1495  */
1496 struct ConnectContext
1497 {
1498   /**
1499    * Testing handle to the first daemon.
1500    */
1501   struct GNUNET_TESTING_Daemon *d1;
1502
1503   /**
1504    * Handle to core of first daemon (to check connect)
1505    */
1506   struct GNUNET_CORE_Handle *d1core;
1507
1508   /**
1509    * Have we actually connected to the core of the first daemon yet?
1510    */
1511   int d1core_ready;
1512
1513   /**
1514    * Testing handle to the second daemon.
1515    */
1516   struct GNUNET_TESTING_Daemon *d2;
1517
1518   /**
1519    * Handler for the request to core to connect to this peer.
1520    */
1521   struct GNUNET_CORE_PeerRequestHandle *connect_request_handle;
1522
1523   /**
1524    * Transport handle to the first daemon (to offer the HELLO of the second daemon to).
1525    */
1526   struct GNUNET_TRANSPORT_Handle *d1th;
1527
1528   /**
1529    * Function to call once we are done (or have timed out).
1530    */
1531   GNUNET_TESTING_NotifyConnection cb;
1532
1533   /**
1534    * Closure for "nb".
1535    */
1536   void *cb_cls;
1537
1538   /**
1539    * The relative timeout from whence this connect attempt was
1540    * started.  Allows for reconnect attempts.
1541    */
1542   struct GNUNET_TIME_Relative relative_timeout;
1543
1544   /**
1545    * Maximum number of connect attempts, will retry connection
1546    * this number of times on failures.
1547    */
1548   unsigned int connect_attempts;
1549
1550   /**
1551    * Hello timeout task
1552    */
1553   GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
1554
1555   /**
1556    * Connect timeout task
1557    */
1558   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1559
1560   /**
1561    * When should this operation be complete (or we must trigger
1562    * a timeout).
1563    */
1564   struct GNUNET_TIME_Relative timeout_hello;
1565
1566   /**
1567    * Was the connection attempt successful?
1568    */
1569   int connected;
1570
1571   /**
1572    * When connecting, do we need to send the HELLO?
1573    */
1574   int send_hello;
1575
1576   /**
1577    * The distance between the two connected peers
1578    */
1579   uint32_t distance;
1580 };
1581
1582
1583 /** Forward declaration **/
1584 static void
1585 reattempt_daemons_connect (void *cls,
1586                            const struct GNUNET_SCHEDULER_TaskContext *tc);
1587
1588
1589 /**
1590  * Notify callback about success or failure of the attempt
1591  * to connect the two peers
1592  *
1593  * @param cls our "struct ConnectContext" (freed)
1594  * @param tc reason tells us if we succeeded or failed
1595  */
1596 static void
1597 notify_connect_result (void *cls,
1598                        const struct GNUNET_SCHEDULER_TaskContext *tc)
1599 {
1600   struct ConnectContext *ctx = cls;
1601   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1602   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1603     {
1604       GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1605       ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1606     }
1607
1608   if (ctx->connect_request_handle != NULL)
1609     {
1610       GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle);
1611       ctx->connect_request_handle = NULL;
1612     }
1613
1614   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1615     {
1616       if (ctx->d1th != NULL)
1617         GNUNET_TRANSPORT_disconnect (ctx->d1th);
1618       ctx->d1th = NULL;
1619       if (ctx->d1core != NULL)
1620         GNUNET_CORE_disconnect (ctx->d1core);
1621 #if CONNECT_CORE2
1622       if (ctx->d2core != NULL)
1623         GNUNET_CORE_disconnect (ctx->d2core);
1624       ctx->d2core = NULL;
1625 #endif
1626       ctx->d1core = NULL;
1627       GNUNET_free (ctx);
1628       return;
1629     }
1630
1631   if (ctx->d1th != NULL)
1632     GNUNET_TRANSPORT_disconnect (ctx->d1th);
1633   ctx->d1th = NULL;
1634   if (ctx->d1core != NULL)
1635     GNUNET_CORE_disconnect (ctx->d1core);
1636   ctx->d1core = NULL;
1637
1638   if (ctx->connected == GNUNET_YES)
1639     {
1640       if (ctx->cb != NULL)
1641         {
1642           ctx->cb (ctx->cb_cls,
1643                    &ctx->d1->id,
1644                    &ctx->d2->id,
1645                    ctx->distance,
1646                    ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
1647         }
1648     }
1649   else if (ctx->connect_attempts > 0)
1650     {
1651       ctx->d1core_ready = GNUNET_NO;
1652 #if CONNECT_CORE2
1653       if (ctx->d2core != NULL)
1654         {
1655           GNUNET_CORE_disconnect (ctx->d2core);
1656           ctx->d2core = NULL;
1657         }
1658 #endif
1659       GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx);
1660       return;
1661     }
1662   else
1663     {
1664       if (ctx->cb != NULL)
1665         {
1666           ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1667                    ctx->d2->cfg, ctx->d1, ctx->d2,
1668                    _("Peers failed to connect"));
1669         }
1670     }
1671
1672   GNUNET_free (ctx);
1673 }
1674
1675
1676 /**
1677  * Success, connection is up.  Signal client our success.
1678  *
1679  * @param cls our "struct ConnectContext"
1680  * @param peer identity of the peer that has connected
1681  * @param atsi performance information
1682  *
1683  */
1684 static void
1685 connect_notify (void *cls,
1686                 const struct GNUNET_PeerIdentity *peer,
1687                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1688 {
1689   struct ConnectContext *ctx = cls;
1690
1691 #if DEBUG_TESTING
1692   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1693                 "Connected peer %s to peer %s\n",
1694                 ctx->d1->shortname, GNUNET_i2s(peer));
1695 #endif
1696
1697   if (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))
1698     {
1699
1700       ctx->connected = GNUNET_YES;
1701       ctx->distance = 0;        /* FIXME: distance */
1702       if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1703         {
1704           GNUNET_SCHEDULER_cancel(ctx->hello_send_task);
1705           ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1706         }
1707       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
1708       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1709                                                     ctx);
1710     }
1711 }
1712
1713 #if CONNECT_CORE2
1714 /**
1715  * Success, connection is up.  Signal client our success.
1716  *
1717  * @param cls our "struct ConnectContext"
1718  * @param peer identity of the peer that has connected
1719  * @param atsi performance information
1720  *
1721  */
1722 static void
1723 connect_notify_core2 (void *cls,
1724                       const struct GNUNET_PeerIdentity *peer,
1725                       const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1726 {
1727   struct ConnectContext *ctx = cls;
1728
1729   if (memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
1730     {
1731       ctx->connected = GNUNET_YES;
1732       ctx->distance = 0;        /* FIXME: distance */
1733       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
1734       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1735                                                     ctx);
1736     }
1737
1738 }
1739 #endif
1740
1741 /**
1742  * Task called once a core connect request has been transmitted.
1743  *
1744  * @param cls struct ConnectContext
1745  * @param success was the request successful?
1746  */
1747 void
1748 core_connect_request_cont (void *cls,
1749                            int success)
1750 {
1751   struct ConnectContext *ctx = cls;
1752
1753   ctx->connect_request_handle = NULL;
1754 }
1755
1756 static void
1757 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1758 {
1759   struct ConnectContext *ctx = cls;
1760   struct GNUNET_MessageHeader *hello;
1761   ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1762   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1763     return;
1764   if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL)
1765       && (NULL != GNUNET_HELLO_get_header (ctx->d2->hello))
1766       && (ctx->d1->phase == SP_START_DONE)
1767       && (ctx->d2->phase == SP_START_DONE))
1768     {
1769       hello = GNUNET_HELLO_get_header (ctx->d2->hello);
1770       GNUNET_assert (hello != NULL);
1771 #if DEBUG_TESTING
1772       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", ctx->d2->shortname, ctx->d1->shortname);
1773 #endif
1774       GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL);
1775       GNUNET_assert (ctx->d1core != NULL);
1776       ctx->connect_request_handle =
1777         GNUNET_CORE_peer_request_connect (ctx->d1core,
1778                                           ctx->relative_timeout,
1779                                           &ctx->d2->id,
1780                                           &core_connect_request_cont, ctx);
1781
1782 #if DEBUG_TESTING
1783       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1784                   "Sending connect request to CORE of %s for peer %s\n",
1785                   GNUNET_i2s (&ctx->d1->id),
1786                   GNUNET_h2s (&ctx->d2->id.hashPubKey));
1787 #endif
1788       ctx->timeout_hello =
1789         GNUNET_TIME_relative_add (ctx->timeout_hello,
1790                                   GNUNET_TIME_relative_multiply
1791                                   (GNUNET_TIME_UNIT_MILLISECONDS, 500));
1792     }
1793   ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello,
1794                                                        &send_hello, ctx);
1795 }
1796
1797 /**
1798  * Notify of a successful connection to the core service.
1799  *
1800  * @param cls a ConnectContext
1801  * @param server handle to the core service
1802  * @param my_identity the peer identity of this peer
1803  * @param publicKey the public key of the peer
1804  */
1805 void
1806 core_init_notify (void *cls,
1807                   struct GNUNET_CORE_Handle * server,
1808                   const struct GNUNET_PeerIdentity *
1809                   my_identity,
1810                   const struct
1811                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
1812                   publicKey)
1813 {
1814   struct ConnectContext *connect_ctx = cls;
1815   connect_ctx->d1core_ready = GNUNET_YES;
1816
1817   if (connect_ctx->send_hello == GNUNET_NO)
1818     {
1819       connect_ctx->connect_request_handle =
1820           GNUNET_CORE_peer_request_connect (connect_ctx->d1core,
1821                                             connect_ctx->relative_timeout,
1822                                             &connect_ctx->d2->id,
1823                                             &core_connect_request_cont, connect_ctx);
1824       GNUNET_assert(connect_ctx->connect_request_handle != NULL);
1825 #if DEBUG_TESTING
1826       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1827                   "Sending connect request to CORE of %s for peer %s\n",
1828                   connect_ctx->d1->shortname,
1829                   connect_ctx->d2->shortname);
1830 #endif
1831     }
1832
1833 }
1834
1835
1836 static void
1837 reattempt_daemons_connect (void *cls,
1838                            const struct GNUNET_SCHEDULER_TaskContext *tc)
1839 {
1840   struct ConnectContext *ctx = cls;
1841   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1842     {
1843       GNUNET_free(ctx);
1844       return;
1845     }
1846 #if DEBUG_TESTING_RECONNECT
1847   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1848               "re-attempting connect of peer %s to peer %s\n",
1849               ctx->d1->shortname, ctx->d2->shortname);
1850 #endif
1851   ctx->connect_attempts--;
1852   GNUNET_assert (ctx->d1core == NULL);
1853   ctx->d1core_ready = GNUNET_NO;
1854   ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
1855                                      ctx,
1856                                      &core_init_notify,
1857                                      &connect_notify, NULL, NULL,
1858                                      NULL, GNUNET_NO,
1859                                      NULL, GNUNET_NO, no_handlers);
1860   if (ctx->d1core == NULL)
1861     {
1862       if (NULL != ctx->cb)
1863         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1864                  ctx->d2->cfg, ctx->d1, ctx->d2,
1865                  _("Failed to connect to core service of first peer!\n"));
1866       GNUNET_free (ctx);
1867       return;
1868     }
1869
1870   if (ctx->send_hello == GNUNET_YES)
1871     {
1872       ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
1873                                             &ctx->d1->id,
1874                                             ctx->d1, NULL, NULL, NULL);
1875       if (ctx->d1th == NULL)
1876         {
1877           GNUNET_CORE_disconnect (ctx->d1core);
1878           GNUNET_free (ctx);
1879           if (NULL != ctx->cb)
1880             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1881                      ctx->d2->cfg, ctx->d1, ctx->d2,
1882                      _("Failed to connect to transport service!\n"));
1883           return;
1884         }
1885       ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
1886     }
1887   else
1888     {
1889       ctx->connect_request_handle =
1890         GNUNET_CORE_peer_request_connect (ctx->d1core,
1891                                           ctx->relative_timeout,
1892                                           &ctx->d2->id,
1893                                           &core_connect_request_cont, ctx);
1894     }
1895   ctx->timeout_task =
1896     GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
1897                                   &notify_connect_result, ctx);
1898 }
1899
1900 /**
1901  * Iterator for currently known peers, to ensure
1902  * that we don't try to send duplicate connect
1903  * requests to core.
1904  *
1905  * @param cls our "struct ConnectContext"
1906  * @param peer identity of the peer that has connected,
1907  *        NULL when iteration has finished
1908  * @param atsi performance information
1909  *
1910  */
1911 static void
1912 core_initial_iteration (void *cls,
1913                         const struct GNUNET_PeerIdentity *peer,
1914                         const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1915 {
1916   struct ConnectContext *ctx = cls;
1917
1918   if ((peer != NULL) &&
1919       (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))))
1920     {
1921       ctx->connected = GNUNET_YES;
1922       ctx->distance = 0;        /* FIXME: distance */
1923       return;
1924     }
1925   else if (peer == NULL) /* End of iteration over peers */
1926     {
1927       if (ctx->connected == GNUNET_YES)
1928         {
1929           ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1930                                                         ctx);
1931           return;
1932         }
1933
1934       /* Peer not already connected, need to schedule connect request! */
1935       if (ctx->d1core == NULL)
1936         {
1937 #if DEBUG_TESTING
1938           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1939                       "Peers are NOT connected, connecting to core!\n");
1940 #endif
1941           ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
1942                                              ctx,
1943                                              &core_init_notify,
1944                                              &connect_notify, NULL, NULL,
1945                                              NULL, GNUNET_NO,
1946                                              NULL, GNUNET_NO, no_handlers);
1947         }
1948
1949       if (ctx->d1core == NULL)
1950         {
1951           GNUNET_free (ctx);
1952           if (NULL != ctx->cb)
1953             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1954                 _("Failed to connect to core service of first peer!\n"));
1955           return;
1956         }
1957
1958       if (ctx->send_hello == GNUNET_YES)
1959         {
1960           ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
1961                                                 &ctx->d1->id, ctx->d1, NULL, NULL, NULL);
1962           if (ctx->d1th == NULL)
1963             {
1964               GNUNET_CORE_disconnect (ctx->d1core);
1965               GNUNET_free (ctx);
1966               if (NULL != ctx->cb)
1967                 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1968                     _("Failed to connect to transport service!\n"));
1969               return;
1970             }
1971           ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
1972         }
1973
1974       ctx->timeout_task =
1975         GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
1976                                       &notify_connect_result, ctx);
1977     }
1978 }
1979
1980
1981 /**
1982  * Establish a connection between two GNUnet daemons.
1983  *
1984  * @param d1 handle for the first daemon
1985  * @param d2 handle for the second daemon
1986  * @param timeout how long is the connection attempt
1987  *        allowed to take?
1988  * @param max_connect_attempts how many times should we try to reconnect
1989  *        (within timeout)
1990  * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume
1991  *                   the HELLO has already been exchanged
1992  * @param cb function to call at the end
1993  * @param cb_cls closure for cb
1994  */
1995 void
1996 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
1997                                 struct GNUNET_TESTING_Daemon *d2,
1998                                 struct GNUNET_TIME_Relative timeout,
1999                                 unsigned int max_connect_attempts,
2000                                 int send_hello,
2001                                 GNUNET_TESTING_NotifyConnection cb,
2002                                 void *cb_cls)
2003 {
2004   struct ConnectContext *ctx;
2005
2006   if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
2007     {
2008       if (NULL != cb)
2009         cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2,
2010             _("Peers are not fully running yet, can not connect!\n"));
2011       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n");
2012       return;
2013     }
2014
2015   ctx = GNUNET_malloc (sizeof (struct ConnectContext));
2016   ctx->d1 = d1;
2017   ctx->d2 = d2;
2018   ctx->timeout_hello =
2019     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
2020   ctx->relative_timeout = GNUNET_TIME_relative_divide(timeout, max_connect_attempts);
2021   ctx->cb = cb;
2022   ctx->cb_cls = cb_cls;
2023   ctx->connect_attempts = max_connect_attempts;
2024   ctx->connected = GNUNET_NO;
2025   ctx->send_hello = send_hello;
2026 #if DEBUG_TESTING
2027   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2028               "Asked to connect peer %s to peer %s\n",
2029               d1->shortname, d2->shortname);
2030 #endif
2031
2032   /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */
2033   GNUNET_assert(GNUNET_OK == GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx));
2034   /*GNUNET_assert(GNUNET_OK == GNUNET_CORE_iterate_peers (ctx->d1->cfg, &core_initial_iteration, ctx));*/
2035 }
2036
2037 /* end of testing.c */