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