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