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