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