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