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