gnunet-arm is too smart for its own good
[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_SERVICE_START:
788       /* confirm gnunet-arm exited */
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               cb = d->cb;
795               d->cb = NULL;
796               if (NULL != cb)
797                 cb (d->cb_cls,
798                     NULL,
799                     d->cfg,
800                     d,
801                     (NULL == d->hostname)
802                     ? _("`gnunet-arm' does not seem to terminate.\n")
803                     : _("`ssh' does not seem to terminate.\n"));
804               return;
805             }
806           /* wait some more */
807           d->task
808             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
809                                             &start_fsm, d);
810           return;
811         }
812 #if EXTRA_CHECKS
813       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
814         {
815           cb = d->cb;
816           d->cb = NULL;
817           if (NULL != cb)
818             cb (d->cb_cls,
819                 NULL,
820                 d->cfg,
821                 d,
822                 (NULL == d->hostname)
823                 ? _("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n")
824                 : _("`ssh' does not seem to terminate.\n"));
825           return;
826         }
827 #endif
828 #if DEBUG_TESTING
829       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n");
830 #endif
831       cb = d->cb;
832       d->cb = NULL;
833       d->phase = SP_START_DONE;
834       if (NULL != cb)
835         cb (d->cb_cls, &d->id, d->cfg, d, NULL);
836       break;
837     case SP_SERVICE_SHUTDOWN_START:
838       /* confirm copying complete */
839       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
840         {
841           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
842               0)
843             {
844               if (NULL != d->dead_cb)
845                 d->dead_cb (d->dead_cb_cls,
846                             _
847                             ("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
848               return;
849             }
850           /* wait some more */
851           d->task
852             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
853                                             &start_fsm, d);
854           return;
855         }
856 #if EXTRA_CHECKS
857       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
858         {
859           if (NULL != d->dead_cb)
860             d->dead_cb (d->dead_cb_cls,
861                         _
862                         ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
863           return;
864         }
865 #endif
866 #if DEBUG_TESTING
867       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
868 #endif
869       if (NULL != d->dead_cb)
870         d->dead_cb (d->dead_cb_cls, NULL);
871       break;
872     case SP_SHUTDOWN_START:
873       /* confirm copying complete */
874       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
875         {
876           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
877               0)
878             {
879               if (NULL != d->dead_cb)
880                 d->dead_cb (d->dead_cb_cls,
881                             _
882                             ("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
883               if (d->th != NULL)
884                 {
885                   GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello,
886                                                      d);
887                   GNUNET_TRANSPORT_disconnect (d->th);
888                   d->th = NULL;
889                 }
890               GNUNET_CONFIGURATION_destroy (d->cfg);
891               GNUNET_free (d->cfgfile);
892               GNUNET_free_non_null (d->hello);
893               GNUNET_free_non_null (d->hostname);
894               GNUNET_free_non_null (d->username);
895               GNUNET_free_non_null (d->shortname);
896               GNUNET_free_non_null (d->proc);
897               d->proc = NULL;
898               GNUNET_free (d);
899               return;
900             }
901           /* wait some more */
902           d->task
903             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
904                                             &start_fsm, d);
905           return;
906         }
907       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
908         {
909           if (NULL != d->dead_cb)
910             d->dead_cb (d->dead_cb_cls,
911                         _
912                         ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
913           if (d->th != NULL)
914             {
915               GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
916               GNUNET_TRANSPORT_disconnect (d->th);
917               d->th = NULL;
918             }
919           if (d->server != NULL)
920             {
921               GNUNET_CORE_disconnect (d->server);
922               d->server = NULL;
923             }
924           GNUNET_CONFIGURATION_destroy (d->cfg);
925           GNUNET_free (d->cfgfile);
926           GNUNET_free_non_null (d->hello);
927           GNUNET_free_non_null (d->hostname);
928           GNUNET_free_non_null (d->username);
929           GNUNET_free_non_null (d->shortname);
930           GNUNET_free_non_null (d->proc);
931           d->proc = NULL;
932           GNUNET_free (d);
933           return;
934         }
935 #if DEBUG_TESTING
936       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n");
937 #endif
938       if (d->server != NULL)
939         {
940           GNUNET_CORE_disconnect (d->server);
941           d->server = NULL;
942         }
943
944       if (d->th != NULL)
945         {
946           GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
947           GNUNET_TRANSPORT_disconnect (d->th);
948           d->th = NULL;
949         }
950
951       if (NULL != d->dead_cb)
952         d->dead_cb (d->dead_cb_cls, NULL);
953
954       /* state clean up and notifications */
955       if (d->churn == GNUNET_NO)
956         {
957           GNUNET_CONFIGURATION_destroy (d->cfg);
958           GNUNET_free (d->cfgfile);
959           GNUNET_free_non_null (d->hostname);
960           GNUNET_free_non_null (d->username);
961         }
962
963       GNUNET_free_non_null (d->hello);
964       d->hello = NULL;
965       GNUNET_free_non_null (d->shortname);
966       GNUNET_free_non_null (d->proc);
967       d->proc = NULL;
968       d->shortname = NULL;
969       if (d->churn == GNUNET_NO)
970         GNUNET_free (d);
971
972       break;
973     case SP_CONFIG_UPDATE:
974       /* confirm copying complete */
975       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
976         {
977           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)       /* FIXME: config update should take timeout parameter! */
978             {
979               cb = d->cb;
980               d->cb = NULL;
981               if (NULL != cb)
982                 cb (d->cb_cls,
983                     NULL,
984                     d->cfg, d, _("`scp' does not seem to terminate.\n"));
985               return;
986             }
987           /* wait some more */
988           d->task
989             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
990                                             &start_fsm, d);
991           return;
992         }
993       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
994         {
995           if (NULL != d->update_cb)
996             d->update_cb (d->update_cb_cls,
997                           _("`scp' did not complete cleanly.\n"));
998           return;
999         }
1000 #if DEBUG_TESTING
1001       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002                   "Successfully copied configuration file.\n");
1003 #endif
1004       if (NULL != d->update_cb)
1005         d->update_cb (d->update_cb_cls, NULL);
1006       d->phase = SP_START_DONE;
1007       break;
1008     }
1009 }
1010
1011 /**
1012  * Continues GNUnet daemon startup when user wanted to be notified
1013  * once a hostkey was generated (for creating friends files, blacklists,
1014  * etc.).
1015  *
1016  * @param daemon the daemon to finish starting
1017  */
1018 void
1019 GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon)
1020 {
1021   GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED);
1022   daemon->phase = SP_TOPOLOGY_SETUP;
1023 }
1024
1025 /**
1026  * Check whether the given daemon is running.
1027  *
1028  * @param daemon the daemon to check
1029  *
1030  * @return GNUNET_YES if the daemon is up, GNUNET_NO if the
1031  *         daemon is down, GNUNET_SYSERR on error.
1032  */
1033 int
1034 GNUNET_TESTING_daemon_running (struct GNUNET_TESTING_Daemon *daemon)
1035 {
1036   if (daemon == NULL)
1037     return GNUNET_SYSERR;
1038
1039   if (daemon->running == GNUNET_YES)
1040     return GNUNET_YES;
1041   return GNUNET_NO;
1042 }
1043
1044
1045 /**
1046  * Stops a GNUnet daemon.
1047  *
1048  * @param d the daemon for which the service should be started
1049  * @param service the name of the service to start
1050  * @param timeout how long to wait for process for shutdown to complete
1051  * @param cb function called once the daemon was stopped
1052  * @param cb_cls closure for cb
1053  */
1054 void
1055 GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d,
1056                                               char *service,
1057                                               struct GNUNET_TIME_Relative timeout,
1058                                               GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls)
1059 {
1060   char *arg;
1061   d->cb = cb;
1062   d->cb_cls = cb_cls;
1063
1064   GNUNET_assert(d->running == GNUNET_YES);
1065
1066   if (d->phase == SP_CONFIG_UPDATE)
1067     {
1068       GNUNET_SCHEDULER_cancel (d->task);
1069       d->phase = SP_START_DONE;
1070     }
1071
1072 #if DEBUG_TESTING
1073   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1075 #endif
1076   if (d->churned_services == NULL)
1077     {
1078       d->dead_cb(d->dead_cb_cls, "No service has been churned off yet!!");
1079       return;
1080     }
1081   d->phase = SP_SERVICE_START;
1082   GNUNET_free(d->churned_services);
1083   d->churned_services = NULL;
1084
1085   /* Check if this is a local or remote process */
1086   if (NULL != d->hostname)
1087     {
1088 #if DEBUG_TESTING
1089       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090                   "Starting gnunet-arm with config `%s' on host `%s'.\n",
1091                   d->cfgfile, d->hostname);
1092 #endif
1093
1094       if (d->username != NULL)
1095         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1096       else
1097         arg = GNUNET_strdup (d->hostname);
1098
1099       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1100 #if !DEBUG_TESTING
1101                                          "-q",
1102 #endif
1103                                          arg, "gnunet-arm",
1104 #if DEBUG_TESTING
1105                                          "-L", "DEBUG",
1106 #endif
1107                                          "-c", d->cfgfile, "-i", service, "-q",
1108                                          NULL);
1109       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110                   "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n",
1111                   arg, "gnunet-arm", d->cfgfile, service);
1112       GNUNET_free (arg);
1113     }
1114   else
1115     {
1116 #if DEBUG_TESTING
1117       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1118                   "Starting gnunet-arm with config `%s' locally.\n",
1119                   d->cfgfile);
1120 #endif
1121       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1122                                          "gnunet-arm",
1123 #if DEBUG_TESTING
1124                                          "-L", "DEBUG",
1125 #endif
1126                                          "-c", d->cfgfile, "-i", service, "-q",
1127                                          NULL);
1128     }
1129
1130   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1131   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1132 }
1133
1134 /**
1135  * Start a peer that has previously been stopped using the daemon_stop
1136  * call (and files weren't deleted and the allow restart flag)
1137  *
1138  * @param daemon the daemon to start (has been previously stopped)
1139  * @param timeout how long to wait for restart
1140  * @param cb the callback for notification when the peer is running
1141  * @param cb_cls closure for the callback
1142  */
1143 void
1144 GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon,
1145                                      struct GNUNET_TIME_Relative timeout,
1146                                      GNUNET_TESTING_NotifyDaemonRunning cb,
1147                                      void *cb_cls)
1148 {
1149   if (daemon->running == GNUNET_YES)
1150     {
1151       cb (cb_cls, &daemon->id, daemon->cfg, daemon,
1152           "Daemon already running, can't restart!");
1153       return;
1154     }
1155
1156   daemon->cb = cb;
1157   daemon->cb_cls = cb_cls;
1158   daemon->phase = SP_TOPOLOGY_SETUP;
1159   daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1160
1161   GNUNET_SCHEDULER_add_continuation (&start_fsm,
1162                                      daemon,
1163                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1164 }
1165
1166 /**
1167  * Starts a GNUnet daemon.  GNUnet must be installed on the target
1168  * system and available in the PATH.  The machine must furthermore be
1169  * reachable via "ssh" (unless the hostname is "NULL") without the
1170  * need to enter a password.
1171  *
1172  * @param cfg configuration to use
1173  * @param timeout how long to wait starting up peers
1174  * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO
1175  *                to really start the peer (default)
1176  * @param hostname name of the machine where to run GNUnet
1177  *        (use NULL for localhost).
1178  * @param ssh_username ssh username to use when connecting to hostname
1179  * @param sshport port to pass to ssh process when connecting to hostname
1180  * @param hostkey pointer to a hostkey to be written to disk (instead of being generated)
1181  * @param hostkey_callback function to call once the hostkey has been
1182  *        generated for this peer, but it hasn't yet been started
1183  *        (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start)
1184  * @param hostkey_cls closure for hostkey callback
1185  * @param cb function to call once peer is up, or failed to start
1186  * @param cb_cls closure for cb
1187  * @return handle to the daemon (actual start will be completed asynchronously)
1188  */
1189 struct GNUNET_TESTING_Daemon *
1190 GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
1191                              struct GNUNET_TIME_Relative timeout,
1192                              int pretend,
1193                              const char *hostname,
1194                              const char *ssh_username,
1195                              uint16_t sshport,
1196                              const char *hostkey,
1197                              GNUNET_TESTING_NotifyHostkeyCreated
1198                              hostkey_callback, void *hostkey_cls,
1199                              GNUNET_TESTING_NotifyDaemonRunning cb,
1200                              void *cb_cls)
1201 {
1202   struct GNUNET_TESTING_Daemon *ret;
1203   char *arg;
1204   char *username;
1205   char *servicehome;
1206   char *baseservicehome;
1207   char *slash;
1208   char *hostkeyfile;
1209   char *temp_file_name;
1210   struct GNUNET_DISK_FileHandle *fn;
1211   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
1212   struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
1213
1214   ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon));
1215   ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
1216   if (sshport != 0)
1217     {
1218       GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport);
1219     }
1220   else
1221     ret->ssh_port_str = NULL;
1222
1223   /* Find service home and base service home directories, create it if it doesn't exist */
1224   GNUNET_assert(GNUNET_OK ==
1225                 GNUNET_CONFIGURATION_get_value_string (cfg,
1226                                                        "PATHS",
1227                                                        "SERVICEHOME",
1228                                                        &servicehome));
1229
1230   GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome));
1231   GNUNET_asprintf(&temp_file_name, "%s/gnunet-testing-config", servicehome);
1232   ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name);
1233   GNUNET_free(temp_file_name);
1234 #if DEBUG_TESTING
1235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236               "Setting up peer with configuration file `%s'.\n",
1237               ret->cfgfile);
1238 #endif
1239   if (NULL == ret->cfgfile)
1240     {
1241       GNUNET_free_non_null (ret->ssh_port_str);
1242       GNUNET_free_non_null (ret->hostname);
1243       GNUNET_free (ret);
1244       return NULL;
1245     }
1246   ret->hostkey_callback = hostkey_callback;
1247   ret->hostkey_cls = hostkey_cls;
1248   ret->cb = cb;
1249   ret->cb_cls = cb_cls;
1250   ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1251   ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
1252   GNUNET_CONFIGURATION_set_value_string (ret->cfg,
1253                                          "PATHS",
1254                                          "DEFAULTCONFIG", ret->cfgfile);
1255
1256   if (hostkey != NULL) /* Get the peer identity from the hostkey */
1257     {
1258       private_key = GNUNET_CRYPTO_rsa_decode_key(hostkey, HOSTKEYFILESIZE);
1259       GNUNET_assert(private_key != NULL);
1260       GNUNET_CRYPTO_rsa_key_get_public (private_key,
1261                                         &public_key);
1262       GNUNET_CRYPTO_hash(&public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &ret->id.hashPubKey);
1263       ret->shortname = GNUNET_strdup(GNUNET_i2s(&ret->id));
1264       ret->have_hostkey = GNUNET_YES;
1265       GNUNET_CRYPTO_rsa_key_free(private_key);
1266     }
1267
1268   /* Write hostkey to file, if we were given one */
1269   hostkeyfile = NULL;
1270   if (hostkey != NULL)
1271     {
1272       GNUNET_asprintf(&hostkeyfile, "%s/.hostkey", servicehome);
1273       fn =
1274       GNUNET_DISK_file_open (hostkeyfile,
1275                              GNUNET_DISK_OPEN_READWRITE
1276                              | GNUNET_DISK_OPEN_CREATE,
1277                              GNUNET_DISK_PERM_USER_READ |
1278                              GNUNET_DISK_PERM_USER_WRITE);
1279       GNUNET_assert(fn != NULL);
1280       GNUNET_assert(HOSTKEYFILESIZE == GNUNET_DISK_file_write(fn, hostkey, HOSTKEYFILESIZE));
1281       GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fn));
1282     }
1283
1284   /* write configuration to temporary file */
1285   if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile))
1286     {
1287       if (0 != UNLINK (ret->cfgfile))
1288         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1289                                   "unlink", ret->cfgfile);
1290       GNUNET_CONFIGURATION_destroy (ret->cfg);
1291       GNUNET_free_non_null (ret->hostname);
1292       GNUNET_free (ret->cfgfile);
1293       GNUNET_free (ret);
1294       return NULL;
1295     }
1296   if (ssh_username != NULL)
1297     username = GNUNET_strdup (ssh_username);
1298   if ((ssh_username == NULL) && (GNUNET_OK !=
1299                                  GNUNET_CONFIGURATION_get_value_string (cfg,
1300                                                                         "TESTING",
1301                                                                         "USERNAME",
1302                                                                         &username)))
1303     {
1304       if (NULL != getenv ("USER"))
1305         username = GNUNET_strdup (getenv ("USER"));
1306       else
1307         username = NULL;
1308     }
1309   ret->username = username;
1310
1311   if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */
1312     {
1313       /* copy directory to remote host */
1314       if (NULL != hostname)
1315         {
1316 #if DEBUG_TESTING
1317           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1318                       "Copying configuration directory to host `%s'.\n", hostname);
1319 #endif
1320           baseservicehome = GNUNET_strdup(servicehome);
1321           /* Remove trailing /'s */
1322           while (baseservicehome[strlen(baseservicehome) - 1] == '/')
1323             baseservicehome[strlen(baseservicehome) - 1] = '\0';
1324           /* Find next directory /, jump one ahead */
1325           slash = strrchr(baseservicehome, '/');
1326           if (slash != NULL)
1327             *(++slash) = '\0';
1328
1329           ret->phase = SP_COPYING;
1330           if (NULL != username)
1331             GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome);
1332           else
1333             GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome);
1334           GNUNET_free(baseservicehome);
1335           if (ret->ssh_port_str == NULL)
1336             {
1337               ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp", "-r",
1338 #if !DEBUG_TESTING
1339                                                    "-q",
1340 #endif
1341                                                    servicehome, arg, NULL);
1342 #if DEBUG_TESTING
1343               GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1344                          "copying directory with command scp -r %s %s\n",
1345                          servicehome, 
1346                          arg);
1347 #endif
1348             }
1349           else
1350             {
1351               ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp",
1352                                                    "scp", "-r", "-P", ret->ssh_port_str,
1353     #if !DEBUG_TESTING
1354                                                    "-q",
1355     #endif
1356                                                    servicehome, arg, NULL);
1357             }
1358           GNUNET_free (arg);
1359           if (NULL == ret->proc)
1360             {
1361               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1362                           _
1363                           ("Could not start `%s' process to copy configuration directory.\n"),
1364                           "scp");
1365               if (0 != UNLINK (ret->cfgfile))
1366                 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1367                                           "unlink", ret->cfgfile);
1368               GNUNET_CONFIGURATION_destroy (ret->cfg);
1369               GNUNET_free_non_null (ret->hostname);
1370               GNUNET_free_non_null (ret->username);
1371               GNUNET_free (ret->cfgfile);
1372               GNUNET_free (ret);
1373               if ((hostkey != NULL) && (0 != UNLINK(hostkeyfile)))
1374                 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1375                                           "unlink", hostkeyfile);
1376               GNUNET_free_non_null(hostkeyfile);
1377               GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome));
1378               GNUNET_free(servicehome);
1379               return NULL;
1380             }
1381
1382           ret->task
1383             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1384                                             &start_fsm, ret);
1385           GNUNET_free_non_null(hostkeyfile);
1386           GNUNET_free(servicehome);
1387           return ret;
1388         }
1389 #if DEBUG_TESTING
1390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1391               "No need to copy configuration file since we are running locally.\n");
1392 #endif
1393       ret->phase = SP_COPIED;
1394       GNUNET_SCHEDULER_add_continuation (&start_fsm,
1395                                          ret,
1396                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1397     }
1398   GNUNET_free_non_null(hostkeyfile);
1399   GNUNET_free(servicehome);
1400   return ret;
1401 }
1402
1403
1404 /**
1405  * Restart (stop and start) a GNUnet daemon.
1406  *
1407  * @param d the daemon that should be restarted
1408  * @param cb function called once the daemon is (re)started
1409  * @param cb_cls closure for cb
1410  */
1411 void
1412 GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d,
1413                                GNUNET_TESTING_NotifyDaemonRunning cb,
1414                                void *cb_cls)
1415 {
1416   char *arg;
1417   char *del_arg;
1418
1419   del_arg = NULL;
1420   if (NULL != d->cb)
1421     {
1422       d->dead = GNUNET_YES;
1423       return;
1424     }
1425
1426   d->cb = cb;
1427   d->cb_cls = cb_cls;
1428
1429   if (d->phase == SP_CONFIG_UPDATE)
1430     {
1431       GNUNET_SCHEDULER_cancel (d->task);
1432       d->phase = SP_START_DONE;
1433     }
1434   if (d->server != NULL)
1435     {
1436       GNUNET_CORE_disconnect (d->server);
1437       d->server = NULL;
1438     }
1439
1440   if (d->th != NULL)
1441     {
1442       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1443       GNUNET_TRANSPORT_disconnect (d->th);
1444       d->th = NULL;
1445     }
1446   /* state clean up and notifications */
1447   GNUNET_free_non_null (d->hello);
1448
1449 #if DEBUG_TESTING
1450   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1451               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1452 #endif
1453
1454   d->phase = SP_START_ARMING;
1455
1456   /* Check if this is a local or remote process */
1457   if (NULL != d->hostname)
1458     {
1459 #if DEBUG_TESTING
1460       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1461                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1462                   d->cfgfile, d->hostname);
1463 #endif
1464
1465       if (d->username != NULL)
1466         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1467       else
1468         arg = GNUNET_strdup (d->hostname);
1469
1470       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1471 #if !DEBUG_TESTING
1472                                          "-q",
1473 #endif
1474                                          arg, "gnunet-arm",
1475 #if DEBUG_TESTING
1476                                          "-L", "DEBUG",
1477 #endif
1478                                          "-c", d->cfgfile, "-e", "-r", NULL);
1479       /* Use -r to restart arm and all services */
1480
1481       GNUNET_free (arg);
1482     }
1483   else
1484     {
1485 #if DEBUG_TESTING
1486       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1487                   "Stopping gnunet-arm with config `%s' locally.\n",
1488                   d->cfgfile);
1489 #endif
1490       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1491                                          "gnunet-arm",
1492 #if DEBUG_TESTING
1493                                          "-L", "DEBUG",
1494 #endif
1495                                          "-c", d->cfgfile, "-e", "-r", NULL);
1496     }
1497
1498   GNUNET_free_non_null (del_arg);
1499   d->task
1500     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1501                                     &start_fsm, d);
1502
1503 }
1504
1505
1506 /**
1507  * Stops a GNUnet daemon.
1508  *
1509  * @param d the daemon that should be stopped
1510  * @param service the name of the service to stop
1511  * @param timeout how long to wait for process for shutdown to complete
1512  * @param cb function called once the daemon was stopped
1513  * @param cb_cls closure for cb
1514  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1515  *        to leave them
1516  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1517  *        GNUNET_NO to kill off and clean up for good
1518  */
1519 void
1520 GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d,
1521                                     char *service,
1522                                     struct GNUNET_TIME_Relative timeout,
1523                                     GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
1524 {
1525   char *arg;
1526   d->dead_cb = cb;
1527   d->dead_cb_cls = cb_cls;
1528
1529   GNUNET_assert(d->running == GNUNET_YES);
1530
1531   if (d->phase == SP_CONFIG_UPDATE)
1532     {
1533       GNUNET_SCHEDULER_cancel (d->task);
1534       d->phase = SP_START_DONE;
1535     }
1536
1537 #if DEBUG_TESTING
1538   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1540 #endif
1541   if (d->churned_services != NULL)
1542     {
1543       d->dead_cb(d->dead_cb_cls, "A service has already been turned off!!");
1544       return;
1545     }
1546   d->phase = SP_SERVICE_SHUTDOWN_START;
1547   d->churned_services = GNUNET_strdup(service);
1548
1549   /* Check if this is a local or remote process */
1550   if (NULL != d->hostname)
1551     {
1552 #if DEBUG_TESTING
1553       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1554                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1555                   d->cfgfile, d->hostname);
1556 #endif
1557
1558       if (d->username != NULL)
1559         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1560       else
1561         arg = GNUNET_strdup (d->hostname);
1562
1563       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1564 #if !DEBUG_TESTING
1565                                          "-q",
1566 #endif
1567                                          arg, "gnunet-arm",
1568 #if DEBUG_TESTING
1569                                          "-L", "DEBUG",
1570 #endif
1571                                          "-c", d->cfgfile, "-k", service, "-q",
1572                                          NULL);
1573       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574                   "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n",
1575                   arg, "gnunet-arm", d->cfgfile, service);
1576       GNUNET_free (arg);
1577     }
1578   else
1579     {
1580 #if DEBUG_TESTING
1581       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1582                   "Stopping gnunet-arm with config `%s' locally.\n",
1583                   d->cfgfile);
1584 #endif
1585       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1586                                          "gnunet-arm",
1587 #if DEBUG_TESTING
1588                                          "-L", "DEBUG",
1589 #endif
1590                                          "-c", d->cfgfile, "-k", service, "-q",
1591                                          NULL);
1592     }
1593
1594   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1595   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1596 }
1597
1598
1599 /**
1600  * Stops a GNUnet daemon.
1601  *
1602  * @param d the daemon that should be stopped
1603  * @param timeout how long to wait for process for shutdown to complete
1604  * @param cb function called once the daemon was stopped
1605  * @param cb_cls closure for cb
1606  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1607  *        to leave them
1608  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1609  *        GNUNET_NO to kill off and clean up for good
1610  */
1611 void
1612 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
1613                             struct GNUNET_TIME_Relative timeout,
1614                             GNUNET_TESTING_NotifyCompletion cb, void *cb_cls,
1615                             int delete_files, int allow_restart)
1616 {
1617   char *arg;
1618   char *del_arg;
1619   d->dead_cb = cb;
1620   d->dead_cb_cls = cb_cls;
1621
1622   if (NULL != d->cb)
1623     {
1624 #if DEBUG_TESTING
1625       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1626                   _("Setting d->dead on peer `%4s'\n"), GNUNET_i2s (&d->id));
1627 #endif
1628       d->dead = GNUNET_YES;
1629       return;
1630     }
1631
1632   if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES))    /* Peer has already been stopped in churn context! */
1633     {
1634       /* Free what was left from churning! */
1635       GNUNET_assert (d->cfg != NULL);
1636       GNUNET_CONFIGURATION_destroy (d->cfg);
1637       if (delete_files == GNUNET_YES)
1638         {
1639           if (0 != UNLINK (d->cfgfile))
1640             {
1641               GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink");
1642             }
1643         }
1644       GNUNET_free (d->cfgfile);
1645       GNUNET_free_non_null (d->hostname);
1646       GNUNET_free_non_null (d->username);
1647       if (NULL != d->dead_cb)
1648         d->dead_cb (d->dead_cb_cls, NULL);
1649       GNUNET_free (d);
1650       return;
1651     }
1652
1653   del_arg = NULL;
1654   if (delete_files == GNUNET_YES)
1655     {
1656       GNUNET_asprintf (&del_arg, "-d");
1657     }
1658
1659   if (d->phase == SP_CONFIG_UPDATE)
1660     {
1661       GNUNET_SCHEDULER_cancel (d->task);
1662       d->phase = SP_START_DONE;
1663     }
1664   /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop?
1665   if (d->server != NULL)
1666     {
1667       GNUNET_CORE_disconnect (d->server);
1668       d->server = NULL;
1669     }
1670     */
1671   /* shutdown ARM process (will terminate others) */
1672 #if DEBUG_TESTING
1673   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1674               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1675 #endif
1676   d->phase = SP_SHUTDOWN_START;
1677   d->running = GNUNET_NO;
1678   if (allow_restart == GNUNET_YES)
1679     d->churn = GNUNET_YES;
1680   if (d->th != NULL)
1681     {
1682       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1683       GNUNET_TRANSPORT_disconnect (d->th);
1684       d->th = NULL;
1685     }
1686   /* Check if this is a local or remote process */
1687   if (NULL != d->hostname)
1688     {
1689 #if DEBUG_TESTING
1690       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1691                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1692                   d->cfgfile, d->hostname);
1693 #endif
1694
1695       if (d->username != NULL)
1696         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1697       else
1698         arg = GNUNET_strdup (d->hostname);
1699
1700       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1701 #if !DEBUG_TESTING
1702                                          "-q",
1703 #endif
1704                                          arg, "gnunet-arm",
1705 #if DEBUG_TESTING
1706                                          "-L", "DEBUG",
1707 #endif
1708                                          "-c", d->cfgfile, "-e", "-q",
1709                                          del_arg, NULL);
1710       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711                   "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n",
1712                   arg, "gnunet-arm", d->cfgfile, del_arg);
1713       /* Use -e to end arm, and -d to remove temp files */
1714       GNUNET_free (arg);
1715     }
1716   else
1717     {
1718 #if DEBUG_TESTING
1719       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1720                   "Stopping gnunet-arm with config `%s' locally.\n",
1721                   d->cfgfile);
1722 #endif
1723       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1724                                          "gnunet-arm",
1725 #if DEBUG_TESTING
1726                                          "-L", "DEBUG",
1727 #endif
1728                                          "-c", d->cfgfile, "-e", "-q",
1729                                          del_arg, NULL);
1730     }
1731
1732   GNUNET_free_non_null (del_arg);
1733   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1734   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1735 }
1736
1737
1738 /**
1739  * Changes the configuration of a GNUnet daemon.
1740  *
1741  * @param d the daemon that should be modified
1742  * @param cfg the new configuration for the daemon
1743  * @param cb function called once the configuration was changed
1744  * @param cb_cls closure for cb
1745  */
1746 void
1747 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
1748                                    struct GNUNET_CONFIGURATION_Handle *cfg,
1749                                    GNUNET_TESTING_NotifyCompletion cb,
1750                                    void *cb_cls)
1751 {
1752   char *arg;
1753
1754   if (d->phase != SP_START_DONE)
1755     {
1756       if (NULL != cb)
1757         cb (cb_cls,
1758             _
1759             ("Peer not yet running, can not change configuration at this point."));
1760       return;
1761     }
1762
1763   /* 1) write configuration to temporary file */
1764   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
1765     {
1766       if (NULL != cb)
1767         cb (cb_cls, _("Failed to write new configuration to disk."));
1768       return;
1769     }
1770
1771   /* 2) copy file to remote host (if necessary) */
1772   if (NULL == d->hostname)
1773     {
1774       /* signal success */
1775       if (NULL != cb)
1776         cb (cb_cls, NULL);
1777       return;
1778     }
1779 #if DEBUG_TESTING
1780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1781               "Copying updated configuration file to remote host `%s'.\n",
1782               d->hostname);
1783 #endif
1784   d->phase = SP_CONFIG_UPDATE;
1785   if (NULL != d->username)
1786     GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
1787   else
1788     GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
1789   d->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
1790 #if !DEBUG_TESTING
1791                                      "-q",
1792 #endif
1793                                      d->cfgfile, arg, NULL);
1794   GNUNET_free (arg);
1795   if (NULL == d->proc)
1796     {
1797       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1798                   _
1799                   ("Could not start `%s' process to copy configuration file.\n"),
1800                   "scp");
1801       if (NULL != cb)
1802         cb (cb_cls, _("Failed to copy new configuration to remote machine."));
1803       d->phase = SP_START_DONE;
1804       return;
1805     }
1806   d->update_cb = cb;
1807   d->update_cb_cls = cb_cls;
1808   d->task
1809     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1810                                     &start_fsm, d);
1811 }
1812
1813
1814 /**
1815  * Data kept for each pair of peers that we try
1816  * to connect.
1817  */
1818 struct ConnectContext
1819 {
1820   /**
1821    * Testing handle to the first daemon.
1822    */
1823   struct GNUNET_TESTING_Daemon *d1;
1824
1825   /**
1826    * Handle to core of first daemon (to check connect)
1827    */
1828   struct GNUNET_CORE_Handle *d1core;
1829
1830   /**
1831    * Have we actually connected to the core of the first daemon yet?
1832    */
1833   int d1core_ready;
1834
1835   /**
1836    * Testing handle to the second daemon.
1837    */
1838   struct GNUNET_TESTING_Daemon *d2;
1839
1840   /**
1841    * Handler for the request to core to connect to this peer.
1842    */
1843   struct GNUNET_CORE_PeerRequestHandle *connect_request_handle;
1844
1845   /**
1846    * Transport handle to the first daemon (to offer the HELLO of the second daemon to).
1847    */
1848   struct GNUNET_TRANSPORT_Handle *d1th;
1849
1850   /**
1851    * Function to call once we are done (or have timed out).
1852    */
1853   GNUNET_TESTING_NotifyConnection cb;
1854
1855   /**
1856    * Closure for "nb".
1857    */
1858   void *cb_cls;
1859
1860   /**
1861    * The relative timeout from whence this connect attempt was
1862    * started.  Allows for reconnect attempts.
1863    */
1864   struct GNUNET_TIME_Relative relative_timeout;
1865
1866   /**
1867    * Maximum number of connect attempts, will retry connection
1868    * this number of times on failures.
1869    */
1870   unsigned int connect_attempts;
1871
1872   /**
1873    * Hello timeout task
1874    */
1875   GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
1876
1877   /**
1878    * Connect timeout task
1879    */
1880   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1881
1882   /**
1883    * When should this operation be complete (or we must trigger
1884    * a timeout).
1885    */
1886   struct GNUNET_TIME_Relative timeout_hello;
1887
1888   /**
1889    * Was the connection attempt successful?
1890    */
1891   int connected;
1892
1893   /**
1894    * When connecting, do we need to send the HELLO?
1895    */
1896   int send_hello;
1897
1898   /**
1899    * The distance between the two connected peers
1900    */
1901   uint32_t distance;
1902 };
1903
1904
1905 /** Forward declaration **/
1906 static void
1907 reattempt_daemons_connect (void *cls,
1908                            const struct GNUNET_SCHEDULER_TaskContext *tc);
1909
1910
1911 /**
1912  * Notify callback about success or failure of the attempt
1913  * to connect the two peers
1914  *
1915  * @param cls our "struct ConnectContext" (freed)
1916  * @param tc reason tells us if we succeeded or failed
1917  */
1918 static void
1919 notify_connect_result (void *cls,
1920                        const struct GNUNET_SCHEDULER_TaskContext *tc)
1921 {
1922   struct ConnectContext *ctx = cls;
1923   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1924   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1925     {
1926       GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1927       ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1928     }
1929
1930   if (ctx->connect_request_handle != NULL)
1931     {
1932       GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle);
1933       ctx->connect_request_handle = NULL;
1934     }
1935
1936   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1937     {
1938       if (ctx->d1th != NULL)
1939         GNUNET_TRANSPORT_disconnect (ctx->d1th);
1940       ctx->d1th = NULL;
1941       if (ctx->d1core != NULL)
1942         GNUNET_CORE_disconnect (ctx->d1core);
1943 #if CONNECT_CORE2
1944       if (ctx->d2core != NULL)
1945         GNUNET_CORE_disconnect (ctx->d2core);
1946       ctx->d2core = NULL;
1947 #endif
1948       ctx->d1core = NULL;
1949       GNUNET_free (ctx);
1950       return;
1951     }
1952
1953   if (ctx->d1th != NULL)
1954     GNUNET_TRANSPORT_disconnect (ctx->d1th);
1955   ctx->d1th = NULL;
1956   if (ctx->d1core != NULL)
1957     GNUNET_CORE_disconnect (ctx->d1core);
1958   ctx->d1core = NULL;
1959
1960   if (ctx->connected == GNUNET_YES)
1961     {
1962       if (ctx->cb != NULL)
1963         {
1964           ctx->cb (ctx->cb_cls,
1965                    &ctx->d1->id,
1966                    &ctx->d2->id,
1967                    ctx->distance,
1968                    ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
1969         }
1970     }
1971   else if (ctx->connect_attempts > 0)
1972     {
1973       ctx->d1core_ready = GNUNET_NO;
1974 #if CONNECT_CORE2
1975       if (ctx->d2core != NULL)
1976         {
1977           GNUNET_CORE_disconnect (ctx->d2core);
1978           ctx->d2core = NULL;
1979         }
1980 #endif
1981       GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx);
1982       return;
1983     }
1984   else
1985     {
1986       if (ctx->cb != NULL)
1987         {
1988           ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1989                    ctx->d2->cfg, ctx->d1, ctx->d2,
1990                    _("Peers failed to connect"));
1991         }
1992     }
1993
1994   GNUNET_free (ctx);
1995 }
1996
1997
1998 /**
1999  * Success, connection is up.  Signal client our success.
2000  *
2001  * @param cls our "struct ConnectContext"
2002  * @param peer identity of the peer that has connected
2003  * @param atsi performance information
2004  *
2005  */
2006 static void
2007 connect_notify (void *cls,
2008                 const struct GNUNET_PeerIdentity *peer,
2009                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2010 {
2011   struct ConnectContext *ctx = cls;
2012
2013 #if DEBUG_TESTING
2014   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2015                 "Connected peer %s to peer %s\n",
2016                 ctx->d1->shortname, GNUNET_i2s(peer));
2017 #endif
2018
2019   if (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))
2020     {
2021
2022       ctx->connected = GNUNET_YES;
2023       ctx->distance = 0;        /* FIXME: distance */
2024       if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
2025         {
2026           GNUNET_SCHEDULER_cancel(ctx->hello_send_task);
2027           ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
2028         }
2029       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
2030       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
2031                                                     ctx);
2032     }
2033 }
2034
2035 #if CONNECT_CORE2
2036 /**
2037  * Success, connection is up.  Signal client our success.
2038  *
2039  * @param cls our "struct ConnectContext"
2040  * @param peer identity of the peer that has connected
2041  * @param atsi performance information
2042  *
2043  */
2044 static void
2045 connect_notify_core2 (void *cls,
2046                       const struct GNUNET_PeerIdentity *peer,
2047                       const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2048 {
2049   struct ConnectContext *ctx = cls;
2050
2051   if (memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
2052     {
2053       ctx->connected = GNUNET_YES;
2054       ctx->distance = 0;        /* FIXME: distance */
2055       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
2056       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
2057                                                     ctx);
2058     }
2059
2060 }
2061 #endif
2062
2063 /**
2064  * Task called once a core connect request has been transmitted.
2065  *
2066  * @param cls struct ConnectContext
2067  * @param success was the request successful?
2068  */
2069 void
2070 core_connect_request_cont (void *cls,
2071                            int success)
2072 {
2073   struct ConnectContext *ctx = cls;
2074
2075   ctx->connect_request_handle = NULL;
2076 }
2077
2078 static void
2079 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2080 {
2081   struct ConnectContext *ctx = cls;
2082   struct GNUNET_MessageHeader *hello;
2083   ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
2084   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2085     return;
2086   if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL)
2087       && (NULL != GNUNET_HELLO_get_header (ctx->d2->hello))
2088       && (ctx->d1->phase == SP_START_DONE)
2089       && (ctx->d2->phase == SP_START_DONE))
2090     {
2091       hello = GNUNET_HELLO_get_header (ctx->d2->hello);
2092       GNUNET_assert (hello != NULL);
2093 #if DEBUG_TESTING
2094       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", ctx->d2->shortname, ctx->d1->shortname);
2095 #endif
2096       GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL);
2097       GNUNET_assert (ctx->d1core != NULL);
2098       ctx->connect_request_handle =
2099         GNUNET_CORE_peer_request_connect (ctx->d1core,
2100                                           &ctx->d2->id,
2101                                           &core_connect_request_cont, ctx);
2102
2103 #if DEBUG_TESTING
2104       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2105                   "Sending connect request to CORE of %s for peer %s\n",
2106                   GNUNET_i2s (&ctx->d1->id),
2107                   GNUNET_h2s (&ctx->d2->id.hashPubKey));
2108 #endif
2109       ctx->timeout_hello =
2110         GNUNET_TIME_relative_add (ctx->timeout_hello,
2111                                   GNUNET_TIME_relative_multiply
2112                                   (GNUNET_TIME_UNIT_MILLISECONDS, 500));
2113     }
2114   ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello,
2115                                                        &send_hello, ctx);
2116 }
2117
2118 /**
2119  * Notify of a successful connection to the core service.
2120  *
2121  * @param cls a ConnectContext
2122  * @param server handle to the core service
2123  * @param my_identity the peer identity of this peer
2124  * @param publicKey the public key of the peer
2125  */
2126 void
2127 core_init_notify (void *cls,
2128                   struct GNUNET_CORE_Handle * server,
2129                   const struct GNUNET_PeerIdentity *
2130                   my_identity,
2131                   const struct
2132                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
2133                   publicKey)
2134 {
2135   struct ConnectContext *connect_ctx = cls;
2136   connect_ctx->d1core_ready = GNUNET_YES;
2137
2138   if (connect_ctx->send_hello == GNUNET_NO)
2139     {
2140       connect_ctx->connect_request_handle =
2141           GNUNET_CORE_peer_request_connect (connect_ctx->d1core,
2142                                             &connect_ctx->d2->id,
2143                                             &core_connect_request_cont, connect_ctx);
2144       GNUNET_assert(connect_ctx->connect_request_handle != NULL);
2145 #if DEBUG_TESTING
2146       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2147                   "Sending connect request to CORE of %s for peer %s\n",
2148                   connect_ctx->d1->shortname,
2149                   connect_ctx->d2->shortname);
2150 #endif
2151     }
2152
2153 }
2154
2155
2156 static void
2157 reattempt_daemons_connect (void *cls,
2158                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2159 {
2160   struct ConnectContext *ctx = cls;
2161   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2162     {
2163       GNUNET_free(ctx);
2164       return;
2165     }
2166 #if DEBUG_TESTING_RECONNECT
2167   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2168               "re-attempting connect of peer %s to peer %s\n",
2169               ctx->d1->shortname, ctx->d2->shortname);
2170 #endif
2171   ctx->connect_attempts--;
2172   GNUNET_assert (ctx->d1core == NULL);
2173   ctx->d1core_ready = GNUNET_NO;
2174   ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
2175                                      ctx,
2176                                      &core_init_notify,
2177                                      &connect_notify, NULL, NULL,
2178                                      NULL, GNUNET_NO,
2179                                      NULL, GNUNET_NO, no_handlers);
2180   if (ctx->d1core == NULL)
2181     {
2182       if (NULL != ctx->cb)
2183         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2184                  ctx->d2->cfg, ctx->d1, ctx->d2,
2185                  _("Failed to connect to core service of first peer!\n"));
2186       GNUNET_free (ctx);
2187       return;
2188     }
2189
2190   /* Don't know reason for initial connect failure, update the HELLO for the second peer */
2191   if (NULL != ctx->d2->hello)
2192     {
2193       GNUNET_free(ctx->d2->hello);
2194       ctx->d2->hello = NULL;
2195       if (NULL != ctx->d2->th)
2196         {
2197           GNUNET_TRANSPORT_get_hello_cancel(ctx->d2->th, &process_hello, ctx->d2);
2198           GNUNET_TRANSPORT_disconnect(ctx->d2->th);
2199         }
2200       ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL);
2201       GNUNET_assert(ctx->d2->th != NULL);
2202       GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2203     }
2204
2205   if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL))
2206     {
2207       ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL);
2208       if (ctx->d2->th == NULL)
2209         {
2210           GNUNET_CORE_disconnect (ctx->d1core);
2211           GNUNET_free (ctx);
2212           if (NULL != ctx->cb)
2213             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
2214                      _("Failed to connect to transport service!\n"));
2215           return;
2216         }
2217       GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2218     }
2219
2220   if (ctx->send_hello == GNUNET_YES)
2221     {
2222       ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
2223                                             &ctx->d1->id,
2224                                             ctx->d1, NULL, NULL, NULL);
2225       if (ctx->d1th == NULL)
2226         {
2227           GNUNET_CORE_disconnect (ctx->d1core);
2228           GNUNET_free (ctx);
2229           if (NULL != ctx->cb)
2230             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
2231                      ctx->d2->cfg, ctx->d1, ctx->d2,
2232                      _("Failed to connect to transport service!\n"));
2233           return;
2234         }
2235       ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2236     }
2237   else
2238     {
2239       ctx->connect_request_handle =
2240         GNUNET_CORE_peer_request_connect (ctx->d1core,
2241                                           &ctx->d2->id,
2242                                           &core_connect_request_cont, ctx);
2243     }
2244   ctx->timeout_task =
2245     GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2246                                   &notify_connect_result, ctx);
2247 }
2248
2249 /**
2250  * Iterator for currently known peers, to ensure
2251  * that we don't try to send duplicate connect
2252  * requests to core.
2253  *
2254  * @param cls our "struct ConnectContext"
2255  * @param peer identity of the peer that has connected,
2256  *        NULL when iteration has finished
2257  * @param atsi performance information
2258  *
2259  */
2260 static void
2261 core_initial_iteration (void *cls,
2262                         const struct GNUNET_PeerIdentity *peer,
2263                         const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2264 {
2265   struct ConnectContext *ctx = cls;
2266
2267   if ((peer != NULL) &&
2268       (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))))
2269     {
2270       ctx->connected = GNUNET_YES;
2271       ctx->distance = 0;        /* FIXME: distance */
2272       return;
2273     }
2274   else if (peer == NULL) /* End of iteration over peers */
2275     {
2276       if (ctx->connected == GNUNET_YES)
2277         {
2278           ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
2279                                                         ctx);
2280           return;
2281         }
2282
2283       /* Peer not already connected, need to schedule connect request! */
2284       if (ctx->d1core == NULL)
2285         {
2286 #if DEBUG_TESTING
2287           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2288                       "Peers are NOT connected, connecting to core!\n");
2289 #endif
2290           ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
2291                                              ctx,
2292                                              &core_init_notify,
2293                                              &connect_notify, NULL, NULL,
2294                                              NULL, GNUNET_NO,
2295                                              NULL, GNUNET_NO, no_handlers);
2296         }
2297
2298       if (ctx->d1core == NULL)
2299         {
2300           GNUNET_free (ctx);
2301           if (NULL != ctx->cb)
2302             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
2303                 _("Failed to connect to core service of first peer!\n"));
2304           return;
2305         }
2306
2307       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 */
2308         {
2309           ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL);
2310           if (ctx->d2->th == NULL)
2311             {
2312               GNUNET_CORE_disconnect (ctx->d1core);
2313               GNUNET_free (ctx);
2314               if (NULL != ctx->cb)
2315                 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
2316                          _("Failed to connect to transport service!\n"));
2317               return;
2318             }
2319           GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2);
2320         }
2321
2322       if (ctx->send_hello == GNUNET_YES)
2323         {
2324           ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
2325                                                 &ctx->d1->id, ctx->d1, NULL, NULL, NULL);
2326           if (ctx->d1th == NULL)
2327             {
2328               GNUNET_CORE_disconnect (ctx->d1core);
2329               GNUNET_free (ctx);
2330               if (NULL != ctx->cb)
2331                 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
2332                     _("Failed to connect to transport service!\n"));
2333               return;
2334             }
2335           ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
2336         }
2337
2338       ctx->timeout_task =
2339         GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
2340                                       &notify_connect_result, ctx);
2341     }
2342 }
2343
2344
2345 /**
2346  * Establish a connection between two GNUnet daemons.
2347  *
2348  * @param d1 handle for the first daemon
2349  * @param d2 handle for the second daemon
2350  * @param timeout how long is the connection attempt
2351  *        allowed to take?
2352  * @param max_connect_attempts how many times should we try to reconnect
2353  *        (within timeout)
2354  * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume
2355  *                   the HELLO has already been exchanged
2356  * @param cb function to call at the end
2357  * @param cb_cls closure for cb
2358  */
2359 void
2360 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
2361                                 struct GNUNET_TESTING_Daemon *d2,
2362                                 struct GNUNET_TIME_Relative timeout,
2363                                 unsigned int max_connect_attempts,
2364                                 int send_hello,
2365                                 GNUNET_TESTING_NotifyConnection cb,
2366                                 void *cb_cls)
2367 {
2368   struct ConnectContext *ctx;
2369
2370   if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
2371     {
2372       if (NULL != cb)
2373         cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2,
2374             _("Peers are not fully running yet, can not connect!\n"));
2375       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n");
2376       return;
2377     }
2378
2379   ctx = GNUNET_malloc (sizeof (struct ConnectContext));
2380   ctx->d1 = d1;
2381   ctx->d2 = d2;
2382   ctx->timeout_hello =
2383     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
2384   ctx->relative_timeout = GNUNET_TIME_relative_divide(timeout, max_connect_attempts);
2385   ctx->cb = cb;
2386   ctx->cb_cls = cb_cls;
2387   ctx->connect_attempts = max_connect_attempts;
2388   ctx->connected = GNUNET_NO;
2389   ctx->send_hello = send_hello;
2390 #if DEBUG_TESTING
2391   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2392               "Asked to connect peer %s to peer %s\n",
2393               d1->shortname, d2->shortname);
2394 #endif
2395
2396   /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */
2397   GNUNET_assert(GNUNET_OK == GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx));
2398   /*GNUNET_assert(GNUNET_OK == GNUNET_CORE_iterate_peers (ctx->d1->cfg, &core_initial_iteration, ctx));*/
2399 }
2400
2401 /* end of testing.c */