clique topology optimization, progress meter for connecting
[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 #define DEBUG_TESTING_RECONNECT GNUNET_YES
42
43 /**
44  * How long do we wait after starting gnunet-service-arm
45  * for the core service to be alive?
46  */
47 #define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
48
49 /**
50  * How many times are we willing to try to wait for "scp" or
51  * "gnunet-service-arm" to complete (waitpid) before giving up?
52  */
53 #define MAX_EXEC_WAIT_RUNS 250
54
55 static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} };
56
57 /**
58  * Receive the HELLO from one peer, give it to the other
59  * and ask them to connect.
60  *
61  * @param cls "struct ConnectContext"
62  * @param message HELLO message of peer
63  */
64 static void
65 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
66 {
67   struct GNUNET_TESTING_Daemon *daemon = cls;
68   GNUNET_TESTING_NotifyDaemonRunning cb;
69
70   int msize;
71   if (daemon == NULL)
72     return;
73
74   GNUNET_assert (daemon->phase == SP_GET_HELLO);
75
76   cb = daemon->cb;
77   daemon->cb = NULL;
78   if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */
79     GNUNET_SCHEDULER_cancel(daemon->task);
80
81   if (daemon->server != NULL)
82     {
83 #if DEBUG_TESTING
84       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85                   "Received `%s' from transport service of `%4s', disconnecting core!\n",
86                   "HELLO", GNUNET_i2s (&daemon->id));
87 #endif
88       GNUNET_CORE_disconnect (daemon->server);
89       daemon->server = NULL;
90     }
91
92   GNUNET_assert (message != NULL);
93   msize = ntohs (message->size);
94   if (msize < 1)
95     {
96       return;
97     }
98   if (daemon->th != NULL)
99     {
100       GNUNET_TRANSPORT_get_hello_cancel (daemon->th, &process_hello, daemon);
101     }
102 #if DEBUG_TESTING
103   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104               "Received `%s' from transport service of `%4s'\n",
105               "HELLO", GNUNET_i2s (&daemon->id));
106 #endif
107
108   GNUNET_free_non_null (daemon->hello);
109   daemon->hello = GNUNET_malloc (msize);
110   memcpy (daemon->hello, message, msize);
111
112   if (daemon->th != NULL)
113     {
114       GNUNET_TRANSPORT_disconnect (daemon->th);
115       daemon->th = NULL;
116     }
117   daemon->phase = SP_START_DONE;
118
119   if (NULL != cb) /* FIXME: what happens when this callback calls GNUNET_TESTING_daemon_stop? */
120     cb (daemon->cb_cls, &daemon->id, daemon->cfg, daemon, NULL);
121 }
122
123 static void
124 start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
125
126 /**
127  * Function called after GNUNET_CORE_connect has succeeded
128  * (or failed for good).  Note that the private key of the
129  * peer is intentionally not exposed here; if you need it,
130  * your process should try to read the private key file
131  * directly (which should work if you are authorized...).
132  *
133  * @param cls closure
134  * @param server handle to the server, NULL if we failed
135  * @param my_identity ID of this peer, NULL if we failed
136  * @param publicKey public key of this peer, NULL if we failed
137  */
138 static void
139 testing_init (void *cls,
140               struct GNUNET_CORE_Handle *server,
141               const struct GNUNET_PeerIdentity *my_identity,
142               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
143 {
144   struct GNUNET_TESTING_Daemon *d = cls;
145
146   GNUNET_assert (d->phase == SP_START_CORE);
147   d->phase = SP_GET_HELLO;
148
149   if (server == NULL)
150     {
151       d->server = NULL;
152       if (GNUNET_YES == d->dead)
153         GNUNET_TESTING_daemon_stop (d,
154                                     GNUNET_TIME_absolute_get_remaining
155                                     (d->max_timeout), d->dead_cb,
156                                     d->dead_cb_cls, GNUNET_YES, GNUNET_NO);
157       else if (NULL != d->cb)
158         d->cb (d->cb_cls, NULL, d->cfg, d,
159             _("Failed to connect to core service\n"));
160       return;
161     }
162 #if DEBUG_TESTING
163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164               "Successfully started peer `%4s'.\n", GNUNET_i2s (my_identity));
165 #endif
166   d->id = *my_identity;
167   d->shortname = strdup (GNUNET_i2s (my_identity));
168   d->server = server;
169   d->running = GNUNET_YES;
170
171   if (GNUNET_NO == d->running)
172     {
173 #if DEBUG_TESTING
174       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175                   "Peer is dead (d->running == GNUNET_NO)\n");
176 #endif
177       return;
178     }
179 #if DEBUG_TESTING
180   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181               "Successfully started peer `%4s', connecting to transport service.\n",
182               GNUNET_i2s (my_identity));
183 #endif
184
185   d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL);
186   if (d->th == NULL)
187     {
188       if (GNUNET_YES == d->dead)
189         GNUNET_TESTING_daemon_stop (d,
190                                     GNUNET_TIME_absolute_get_remaining
191                                     (d->max_timeout), d->dead_cb,
192                                     d->dead_cb_cls, GNUNET_YES, GNUNET_NO);
193       else if (NULL != d->cb)
194         d->cb (d->cb_cls, &d->id, d->cfg, d,
195                _("Failed to connect to transport service!\n"));
196       return;
197     }
198 #if DEBUG_TESTING
199   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200               "Connected to transport service `%s', getting HELLO\n",
201               GNUNET_i2s (my_identity));
202 #endif
203
204   GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d);
205   /* wait some more */
206   if (d->task != GNUNET_SCHEDULER_NO_TASK)
207     GNUNET_SCHEDULER_cancel(d->task);
208   d->task
209     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
210                                     &start_fsm, d);
211 }
212
213
214 /**
215  * Finite-state machine for starting GNUnet.
216  *
217  * @param cls our "struct GNUNET_TESTING_Daemon"
218  * @param tc unused
219  */
220 static void
221 start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
222 {
223   struct GNUNET_TESTING_Daemon *d = cls;
224   GNUNET_TESTING_NotifyDaemonRunning cb;
225   enum GNUNET_OS_ProcessStatusType type;
226   unsigned long code;
227   char *dst;
228   int bytes_read;
229
230 #if DEBUG_TESTING
231   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232               "Peer FSM is in phase %u.\n", d->phase);
233 #endif
234
235   d->task = GNUNET_SCHEDULER_NO_TASK;
236   switch (d->phase)
237     {
238     case SP_COPYING:
239       /* confirm copying complete */
240       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
241         {
242           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
243               0)
244             {
245               cb = d->cb;
246               d->cb = NULL;
247               if (NULL != cb)
248                 cb (d->cb_cls,
249                     NULL,
250                     d->cfg, d,
251                     _
252                     ("`scp' does not seem to terminate (timeout copying config).\n"));
253               return;
254             }
255           /* wait some more */
256           d->task
257             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
258                                             &start_fsm, d);
259           return;
260         }
261       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
262         {
263           cb = d->cb;
264           d->cb = NULL;
265           if (NULL != cb)
266             cb (d->cb_cls,
267                 NULL, d->cfg, d, _("`scp' did not complete cleanly.\n"));
268           return;
269         }
270 #if DEBUG_TESTING
271       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272                   "Successfully copied configuration file.\n");
273 #endif
274       d->phase = SP_COPIED;
275       /* fall-through */
276     case SP_COPIED:
277       /* Start create hostkey process */
278       d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES);
279       if (d->pipe_stdout == NULL)
280         {
281           cb = d->cb;
282           d->cb = NULL;
283           if (NULL != cb)
284             cb (d->cb_cls,
285                 NULL,
286                 d->cfg,
287                 d,
288                 (NULL == d->hostname)
289                 ? _("Failed to create pipe for `gnunet-peerinfo' process.\n")
290                 : _("Failed to create pipe for `ssh' process.\n"));
291           return;
292         }
293       if (NULL == d->hostname)
294         {
295 #if DEBUG_TESTING
296           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
297                       "Starting `%s', with command `%s %s %s %s'.\n",
298                       "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile,
299                       "-sq");
300 #endif
301           d->proc =
302             GNUNET_OS_start_process (NULL, d->pipe_stdout, "gnunet-peerinfo",
303                                      "gnunet-peerinfo", "-c", d->cfgfile,
304                                      "-sq", NULL);
305           GNUNET_DISK_pipe_close_end (d->pipe_stdout,
306                                       GNUNET_DISK_PIPE_END_WRITE);
307         }
308       else
309         {
310           if (d->username != NULL)
311             GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname);
312           else
313             dst = GNUNET_strdup (d->hostname);
314
315 #if DEBUG_TESTING
316           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317                       "Starting `%s', with command `%s %s %s %s %s %s'.\n",
318                       "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c",
319                       d->cfgfile, "-sq");
320 #endif
321           if (d->ssh_port_str == NULL)
322             {
323               d->proc = GNUNET_OS_start_process (NULL, d->pipe_stdout, "ssh",
324                                                  "ssh",
325 #if !DEBUG_TESTING
326                                                  "-q",
327 #endif
328                                                  dst,
329                                                  "gnunet-peerinfo",
330                                                  "-c", d->cfgfile, "-sq",
331                                                  NULL);
332             }
333           else
334             {
335               d->proc = GNUNET_OS_start_process (NULL, d->pipe_stdout, "ssh",
336                                                  "ssh", "-p", d->ssh_port_str,
337 #if !DEBUG_TESTING
338                                                  "-q",
339 #endif
340                                                  dst,
341                                                  "gnunet-peerinfo",
342                                                  "-c", d->cfgfile, "-sq",
343                                                  NULL);
344             }
345           GNUNET_DISK_pipe_close_end (d->pipe_stdout,
346                                       GNUNET_DISK_PIPE_END_WRITE);
347           GNUNET_free (dst);
348         }
349       if (NULL == d->proc)
350         {
351           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
352                       _("Could not start `%s' process to create hostkey.\n"),
353                       (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh");
354           cb = d->cb;
355           d->cb = NULL;
356           if (NULL != cb)
357             cb (d->cb_cls,
358                 NULL,
359                 d->cfg,
360                 d,
361                 (NULL == d->hostname)
362                 ? _("Failed to start `gnunet-peerinfo' process.\n")
363                 : _("Failed to start `ssh' process.\n"));
364           GNUNET_DISK_pipe_close (d->pipe_stdout);
365           return;
366         }
367 #if DEBUG_TESTING
368       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369                   "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo");
370 #endif
371       d->phase = SP_HOSTKEY_CREATE;
372       d->task
373         =
374         GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
375                                         (d->max_timeout),
376                                         GNUNET_DISK_pipe_handle
377                                         (d->pipe_stdout,
378                                          GNUNET_DISK_PIPE_END_READ),
379                                         &start_fsm, d);
380       break;
381     case SP_HOSTKEY_CREATE:
382       bytes_read =
383         GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle
384                                (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ),
385                                &d->hostkeybuf[d->hostkeybufpos],
386                                sizeof (d->hostkeybuf) - d->hostkeybufpos);
387       if (bytes_read > 0)
388         d->hostkeybufpos += bytes_read;
389
390       if ((d->hostkeybufpos < 104) && (bytes_read > 0))
391         {
392           /* keep reading */
393           d->task
394             =
395             GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
396                                             (d->max_timeout),
397                                             GNUNET_DISK_pipe_handle
398                                             (d->pipe_stdout,
399                                              GNUNET_DISK_PIPE_END_READ),
400                                             &start_fsm, d);
401           return;
402         }
403       d->hostkeybuf[103] = '\0';
404
405       if ((bytes_read < 0) ||
406           (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (d->hostkeybuf,
407                                                         &d->id.hashPubKey)))
408         {
409           /* error */
410           if (bytes_read < 0)
411             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
412                         _("Error reading from gnunet-peerinfo: %s\n"),
413                         STRERROR (errno));
414           else
415             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
416                         _("Malformed output from gnunet-peerinfo!\n"));
417           cb = d->cb;
418           d->cb = NULL;
419           GNUNET_DISK_pipe_close (d->pipe_stdout);
420           d->pipe_stdout = NULL;
421           (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
422           GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
423           GNUNET_OS_process_close (d->proc);
424           d->proc = NULL;
425           if (NULL != cb)
426             cb (d->cb_cls, NULL, d->cfg, d, _("`Failed to get hostkey!\n"));
427           return;
428         }
429       GNUNET_DISK_pipe_close (d->pipe_stdout);
430       d->pipe_stdout = NULL;
431       (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
432       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
433       GNUNET_OS_process_close (d->proc);
434       d->proc = NULL;
435 #if DEBUG_TESTING
436       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n");
437 #endif
438       if (d->hostkey_callback != NULL)
439         {
440           d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL);
441           d->phase = SP_HOSTKEY_CREATED;
442         }
443       else
444         {
445           d->phase = SP_TOPOLOGY_SETUP;
446         }
447       /* Fall through */
448     case SP_HOSTKEY_CREATED:
449       /* wait for topology finished */
450       if ((GNUNET_YES == d->dead)
451           || (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
452               0))
453         {
454           cb = d->cb;
455           d->cb = NULL;
456           if (NULL != cb)
457             cb (d->cb_cls,
458                 NULL,
459                 d->cfg, d, _("`Failed while waiting for topology setup!\n"));
460           return;
461         }
462
463       d->task
464         = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
465                                         &start_fsm, d);
466       break;
467     case SP_TOPOLOGY_SETUP:
468       /* start GNUnet on remote host */
469       if (NULL == d->hostname)
470         {
471 #if DEBUG_TESTING
472           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
473                       "Starting `%s', with command `%s %s %s %s %s %s'.\n",
474                       "gnunet-arm", "gnunet-arm", "-c", d->cfgfile,
475                       "-L", "DEBUG", "-s");
476 #endif
477           d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
478                                              "gnunet-arm", "-c", d->cfgfile,
479 #if DEBUG_TESTING
480                                              "-L", "DEBUG",
481 #endif
482                                              "-s", "-q", NULL);
483         }
484       else
485         {
486           if (d->username != NULL)
487             GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname);
488           else
489             dst = GNUNET_strdup (d->hostname);
490
491 #if DEBUG_TESTING
492           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
493                       "Starting `%s', with command `%s %s %s %s %s %s %s %s'.\n",
494                       "gnunet-arm", "ssh", dst, "gnunet-arm", "-c",
495                       d->cfgfile, "-L", "DEBUG", "-s", "-q");
496 #endif
497           if (d->ssh_port_str == NULL)
498             {
499               d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
500 #if !DEBUG_TESTING
501                                                  "-q",
502 #endif
503                                                  dst, "gnunet-arm",
504 #if DEBUG_TESTING
505                                                  "-L", "DEBUG",
506 #endif
507                                                  "-c", d->cfgfile, "-s", "-q",
508                                                  NULL);
509             }
510           else
511             {
512
513               d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh",
514                                                  "ssh", "-p", d->ssh_port_str,
515 #if !DEBUG_TESTING
516                                                  "-q",
517 #endif
518                                                  dst, "gnunet-arm",
519 #if DEBUG_TESTING
520                                                  "-L", "DEBUG",
521 #endif
522                                                  "-c", d->cfgfile, "-s", "-q",
523                                                  NULL);
524             }
525           GNUNET_free (dst);
526         }
527       if (NULL == d->proc)
528         {
529           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
530                       _("Could not start `%s' process to start GNUnet.\n"),
531                       (NULL == d->hostname) ? "gnunet-arm" : "ssh");
532           cb = d->cb;
533           d->cb = NULL;
534           if (NULL != cb)
535             cb (d->cb_cls,
536                 NULL,
537                 d->cfg,
538                 d,
539                 (NULL == d->hostname)
540                 ? _("Failed to start `gnunet-arm' process.\n")
541                 : _("Failed to start `ssh' process.\n"));
542           return;
543         }
544 #if DEBUG_TESTING
545       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
546                   "Started `%s', waiting for `%s' to be up.\n",
547                   "gnunet-arm", "gnunet-service-core");
548 #endif
549       d->phase = SP_START_ARMING;
550       d->task
551         = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
552                                         &start_fsm, d);
553       break;
554     case SP_START_ARMING:
555       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
556         {
557           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
558               0)
559             {
560               cb = d->cb;
561               d->cb = NULL;
562               if (NULL != cb)
563                 cb (d->cb_cls,
564                     NULL,
565                     d->cfg,
566                     d,
567                     (NULL == d->hostname)
568                     ? _("`gnunet-arm' does not seem to terminate.\n")
569                     : _("`ssh' does not seem to terminate.\n"));
570               GNUNET_CONFIGURATION_destroy (d->cfg);
571               GNUNET_free (d->cfgfile);
572               GNUNET_free_non_null (d->hostname);
573               GNUNET_free_non_null (d->username);
574               GNUNET_free(d->proc);
575               GNUNET_free(d);
576               return;
577             }
578           /* wait some more */
579           d->task
580             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
581                                             &start_fsm, d);
582           return;
583         }
584 #if DEBUG_TESTING
585       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
586                   "Successfully started `%s'.\n", "gnunet-arm");
587 #endif
588       GNUNET_free(d->proc);
589       d->phase = SP_START_CORE;
590 #if DEBUG_TESTING
591       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
592                   "Calling CORE_connect\n");
593 #endif
594       /* Fall through */
595     case SP_START_CORE:
596       if (d->server != NULL)
597         GNUNET_CORE_disconnect(d->server);
598
599       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
600           0)
601         {
602           cb = d->cb;
603           d->cb = NULL;
604           if (NULL != cb)
605             cb (d->cb_cls,
606                 NULL,
607                 d->cfg,
608                 d,
609                 _("Unable to connect to CORE service for peer!\n"));
610           GNUNET_CONFIGURATION_destroy (d->cfg);
611           GNUNET_free (d->cfgfile);
612           GNUNET_free_non_null (d->hostname);
613           GNUNET_free_non_null (d->username);
614           GNUNET_free (d);
615           return;
616         }
617       d->server = GNUNET_CORE_connect (d->cfg, 1,
618                                        d,
619                                        &testing_init,
620                                        NULL, NULL, NULL,
621                                        NULL, GNUNET_NO,
622                                        NULL, GNUNET_NO, no_handlers);
623       d->task
624         = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_CONSTANTS_SERVICE_RETRY, 2),
625                                         &start_fsm, d);
626       break;
627     case SP_GET_HELLO:
628       if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
629           0)
630         {
631           if (d->server != NULL)
632             GNUNET_CORE_disconnect(d->server);
633           if (d->th != NULL)
634             GNUNET_TRANSPORT_disconnect(d->th);
635           cb = d->cb;
636           d->cb = NULL;
637           if (NULL != cb)
638             cb (d->cb_cls,
639                 NULL,
640                 d->cfg,
641                 d,
642                 _("Unable to get HELLO for peer!\n"));
643           GNUNET_CONFIGURATION_destroy (d->cfg);
644           GNUNET_free (d->cfgfile);
645           GNUNET_free_non_null (d->hostname);
646           GNUNET_free_non_null (d->username);
647           GNUNET_free (d);
648           return;
649         }
650       if (d->hello != NULL)
651         return;
652       GNUNET_assert(d->task == GNUNET_SCHEDULER_NO_TASK);
653       d->task
654         = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_CONSTANTS_SERVICE_RETRY, 2),
655                                         &start_fsm, d);
656       break;
657     case SP_START_DONE:
658       GNUNET_break (0);
659       break;
660     case SP_SHUTDOWN_START:
661       /* confirm copying complete */
662       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
663         {
664           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value ==
665               0)
666             {
667               if (NULL != d->dead_cb)
668                 d->dead_cb (d->dead_cb_cls,
669                             _
670                             ("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
671               if (d->th != NULL)
672                 {
673                   GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello,
674                                                      d);
675                   GNUNET_TRANSPORT_disconnect (d->th);
676                   d->th = NULL;
677                 }
678               GNUNET_CONFIGURATION_destroy (d->cfg);
679               GNUNET_free (d->cfgfile);
680               GNUNET_free_non_null (d->hello);
681               GNUNET_free_non_null (d->hostname);
682               GNUNET_free_non_null (d->username);
683               GNUNET_free_non_null (d->shortname);
684               GNUNET_free_non_null (d->proc);
685               d->proc = NULL;
686               GNUNET_free (d);
687               return;
688             }
689           /* wait some more */
690           d->task
691             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
692                                             &start_fsm, d);
693           return;
694         }
695       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
696         {
697           if (NULL != d->dead_cb)
698             d->dead_cb (d->dead_cb_cls,
699                         _
700                         ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
701           if (d->th != NULL)
702             {
703               GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
704               GNUNET_TRANSPORT_disconnect (d->th);
705               d->th = NULL;
706             }
707           if (d->server != NULL)
708             {
709               GNUNET_CORE_disconnect (d->server);
710               d->server = NULL;
711             }
712           GNUNET_CONFIGURATION_destroy (d->cfg);
713           GNUNET_free (d->cfgfile);
714           GNUNET_free_non_null (d->hello);
715           GNUNET_free_non_null (d->hostname);
716           GNUNET_free_non_null (d->username);
717           GNUNET_free_non_null (d->shortname);
718           GNUNET_free_non_null (d->proc);
719           d->proc = NULL;
720           GNUNET_free (d);
721           return;
722         }
723 #if DEBUG_TESTING
724       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n");
725 #endif
726       if (d->server != NULL)
727         {
728           GNUNET_CORE_disconnect (d->server);
729           d->server = NULL;
730         }
731
732       if (d->th != NULL)
733         {
734           GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
735           GNUNET_TRANSPORT_disconnect (d->th);
736           d->th = NULL;
737         }
738       /* state clean up and notifications */
739       if (d->churn == GNUNET_NO)
740         {
741           GNUNET_CONFIGURATION_destroy (d->cfg);
742           GNUNET_free (d->cfgfile);
743           GNUNET_free_non_null (d->hostname);
744           GNUNET_free_non_null (d->username);
745         }
746
747       GNUNET_free_non_null (d->hello);
748       d->hello = NULL;
749       GNUNET_free_non_null (d->shortname);
750       GNUNET_free_non_null (d->proc);
751       d->proc = NULL;
752       d->shortname = NULL;
753       if (NULL != d->dead_cb)
754         d->dead_cb (d->dead_cb_cls, NULL);
755
756       if (d->churn == GNUNET_NO)
757         GNUNET_free (d);
758
759       break;
760     case SP_CONFIG_UPDATE:
761       /* confirm copying complete */
762       if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code))
763         {
764           if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)       /* FIXME: config update should take timeout parameter! */
765             {
766               cb = d->cb;
767               d->cb = NULL;
768               if (NULL != cb)
769                 cb (d->cb_cls,
770                     NULL,
771                     d->cfg, d, _("`scp' does not seem to terminate.\n"));
772               return;
773             }
774           /* wait some more */
775           d->task
776             = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
777                                             &start_fsm, d);
778           return;
779         }
780       if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
781         {
782           if (NULL != d->update_cb)
783             d->update_cb (d->update_cb_cls,
784                           _("`scp' did not complete cleanly.\n"));
785           return;
786         }
787 #if DEBUG_TESTING
788       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789                   "Successfully copied configuration file.\n");
790 #endif
791       if (NULL != d->update_cb)
792         d->update_cb (d->update_cb_cls, NULL);
793       d->phase = SP_START_DONE;
794       break;
795     }
796 }
797
798 /**
799  * Continues GNUnet daemon startup when user wanted to be notified
800  * once a hostkey was generated (for creating friends files, blacklists,
801  * etc.).
802  *
803  * @param daemon the daemon to finish starting
804  */
805 void
806 GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon)
807 {
808   GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED);
809   daemon->phase = SP_TOPOLOGY_SETUP;
810 }
811
812 /**
813  * Check whether the given daemon is running.
814  *
815  * @param daemon the daemon to check
816  *
817  * @return GNUNET_YES if the daemon is up, GNUNET_NO if the
818  *         daemon is down, GNUNET_SYSERR on error.
819  */
820 int
821 GNUNET_TESTING_daemon_running (struct GNUNET_TESTING_Daemon *daemon)
822 {
823   if (daemon == NULL)
824     return GNUNET_SYSERR;
825
826   if (daemon->running == GNUNET_YES)
827     return GNUNET_YES;
828   return GNUNET_NO;
829 }
830
831
832 /**
833  * Start a peer that has previously been stopped using the daemon_stop
834  * call (and files weren't deleted and the allow restart flag)
835  *
836  * @param daemon the daemon to start (has been previously stopped)
837  * @param timeout how long to wait for restart
838  * @param cb the callback for notification when the peer is running
839  * @param cb_cls closure for the callback
840  */
841 void
842 GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon,
843                                      struct GNUNET_TIME_Relative timeout,
844                                      GNUNET_TESTING_NotifyDaemonRunning cb,
845                                      void *cb_cls)
846 {
847   if (daemon->running == GNUNET_YES)
848     {
849       cb (cb_cls, &daemon->id, daemon->cfg, daemon,
850           "Daemon already running, can't restart!");
851       return;
852     }
853
854   daemon->cb = cb;
855   daemon->cb_cls = cb_cls;
856   daemon->phase = SP_TOPOLOGY_SETUP;
857   daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
858
859   GNUNET_SCHEDULER_add_continuation (&start_fsm,
860                                      daemon,
861                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
862 }
863
864 /**
865  * Starts a GNUnet daemon.  GNUnet must be installed on the target
866  * system and available in the PATH.  The machine must furthermore be
867  * reachable via "ssh" (unless the hostname is "NULL") without the
868  * need to enter a password.
869  *
870  * @param cfg configuration to use
871  * @param timeout how long to wait starting up peers
872  * @param hostname name of the machine where to run GNUnet
873  *        (use NULL for localhost).
874  * @param ssh_username ssh username to use when connecting to hostname
875  * @param sshport port to pass to ssh process when connecting to hostname
876  * @param hostkey pointer to a hostkey to be written to disk (instead of being generated)
877  * @param hostkey_callback function to call once the hostkey has been
878  *        generated for this peer, but it hasn't yet been started
879  *        (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start)
880  * @param hostkey_cls closure for hostkey callback
881  * @param cb function to call once peer is up, or failed to start
882  * @param cb_cls closure for cb
883  * @return handle to the daemon (actual start will be completed asynchronously)
884  */
885 struct GNUNET_TESTING_Daemon *
886 GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
887                              struct GNUNET_TIME_Relative timeout,
888                              const char *hostname,
889                              const char *ssh_username,
890                              uint16_t sshport,
891                              const char *hostkey,
892                              GNUNET_TESTING_NotifyHostkeyCreated
893                              hostkey_callback, void *hostkey_cls,
894                              GNUNET_TESTING_NotifyDaemonRunning cb,
895                              void *cb_cls)
896 {
897   struct GNUNET_TESTING_Daemon *ret;
898   char *arg;
899   char *username;
900   char *servicehome;
901   char *baseservicehome;
902   char *slash;
903   char *hostkeyfile;
904   char *temp_file_name;
905   struct GNUNET_DISK_FileHandle *fn;
906
907   ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon));
908   ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
909   if (sshport != 0)
910     {
911       GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport);
912     }
913   else
914     ret->ssh_port_str = NULL;
915
916   /* Find service home and base service home directories, create it if it doesn't exist */
917   GNUNET_assert(GNUNET_OK ==
918                 GNUNET_CONFIGURATION_get_value_string (cfg,
919                                                        "PATHS",
920                                                        "SERVICEHOME",
921                                                        &servicehome));
922
923   GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome));
924   GNUNET_asprintf(&temp_file_name, "%s/gnunet-testing-config", servicehome);
925   ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name);
926   GNUNET_free(temp_file_name);
927 #if DEBUG_TESTING
928   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929               "Setting up peer with configuration file `%s'.\n",
930               ret->cfgfile);
931 #endif
932   if (NULL == ret->cfgfile)
933     {
934       GNUNET_free_non_null (ret->ssh_port_str);
935       GNUNET_free_non_null (ret->hostname);
936       GNUNET_free (ret);
937       return NULL;
938     }
939   ret->hostkey_callback = hostkey_callback;
940   ret->hostkey_cls = hostkey_cls;
941   ret->cb = cb;
942   ret->cb_cls = cb_cls;
943   ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
944   ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
945   GNUNET_CONFIGURATION_set_value_string (ret->cfg,
946                                          "PATHS",
947                                          "DEFAULTCONFIG", ret->cfgfile);
948
949   /* Write hostkey to file, if we were given one */
950   hostkeyfile = NULL;
951   if (hostkey != NULL)
952     {
953       GNUNET_asprintf(&hostkeyfile, "%s/.hostkey", servicehome);
954       fn =
955       GNUNET_DISK_file_open (hostkeyfile,
956                              GNUNET_DISK_OPEN_READWRITE
957                              | GNUNET_DISK_OPEN_CREATE,
958                              GNUNET_DISK_PERM_USER_READ |
959                              GNUNET_DISK_PERM_USER_WRITE);
960       GNUNET_assert(fn != NULL);
961       GNUNET_assert(HOSTKEYFILESIZE == GNUNET_DISK_file_write(fn, hostkey, HOSTKEYFILESIZE));
962       GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fn));
963     }
964
965   /* write configuration to temporary file */
966   if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile))
967     {
968       if (0 != UNLINK (ret->cfgfile))
969         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
970                                   "unlink", ret->cfgfile);
971       GNUNET_CONFIGURATION_destroy (ret->cfg);
972       GNUNET_free_non_null (ret->hostname);
973       GNUNET_free (ret->cfgfile);
974       GNUNET_free (ret);
975       return NULL;
976     }
977   if (ssh_username != NULL)
978     username = GNUNET_strdup (ssh_username);
979   if ((ssh_username == NULL) && (GNUNET_OK !=
980                                  GNUNET_CONFIGURATION_get_value_string (cfg,
981                                                                         "TESTING",
982                                                                         "USERNAME",
983                                                                         &username)))
984     {
985       if (NULL != getenv ("USER"))
986         username = GNUNET_strdup (getenv ("USER"));
987       else
988         username = NULL;
989     }
990   ret->username = username;
991
992   /* copy directory to remote host */
993   if (NULL != hostname)
994     {
995 #if DEBUG_TESTING
996       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997                   "Copying configuration directory to host `%s'.\n", hostname);
998 #endif
999       baseservicehome = GNUNET_strdup(servicehome);
1000       /* Remove trailing /'s */
1001       while (baseservicehome[strlen(baseservicehome) - 1] == '/')
1002         baseservicehome[strlen(baseservicehome) - 1] = '\0';
1003       /* Find next directory /, jump one ahead */
1004       slash = strrchr(baseservicehome, '/');
1005       if (slash != NULL)
1006         *(++slash) = '\0';
1007
1008       ret->phase = SP_COPYING;
1009       if (NULL != username)
1010         GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome);
1011       else
1012         GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome);
1013
1014       if (ret->ssh_port_str == NULL)
1015         {
1016           ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp", "-r",
1017 #if !DEBUG_TESTING
1018                                                "-q",
1019 #endif
1020                                                servicehome, arg, NULL);
1021 #if DEBUG_TESTING
1022           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "copying directory with command scp -r %s %s\n", servicehome, arg);
1023 #endif
1024         }
1025       else
1026         {
1027           ret->proc = GNUNET_OS_start_process (NULL, NULL, "scp",
1028                                                "scp", "-r", "-P", ret->ssh_port_str,
1029 #if !DEBUG_TESTING
1030                                                "-q",
1031 #endif
1032                                                servicehome, arg, NULL);
1033         }
1034       GNUNET_free (arg);
1035       if (NULL == ret->proc)
1036         {
1037           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1038                       _
1039                       ("Could not start `%s' process to copy configuration directory.\n"),
1040                       "scp");
1041           if (0 != UNLINK (ret->cfgfile))
1042             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1043                                       "unlink", ret->cfgfile);
1044           GNUNET_CONFIGURATION_destroy (ret->cfg);
1045           GNUNET_free_non_null (ret->hostname);
1046           GNUNET_free_non_null (ret->username);
1047           GNUNET_free (ret->cfgfile);
1048           GNUNET_free (ret);
1049           if ((hostkey != NULL) && (0 != UNLINK(hostkeyfile)))
1050             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1051                                       "unlink", hostkeyfile);
1052           GNUNET_free_non_null(hostkeyfile);
1053           GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome));
1054           GNUNET_free(servicehome);
1055           return NULL;
1056         }
1057       ret->task
1058         = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1059                                         &start_fsm, ret);
1060       GNUNET_free_non_null(hostkeyfile);
1061       GNUNET_free(servicehome);
1062       return ret;
1063     }
1064 #if DEBUG_TESTING
1065   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066               "No need to copy configuration file since we are running locally.\n");
1067 #endif
1068   ret->phase = SP_COPIED;
1069   GNUNET_SCHEDULER_add_continuation (&start_fsm,
1070                                      ret,
1071                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1072   GNUNET_free_non_null(hostkeyfile);
1073   GNUNET_free(servicehome);
1074   return ret;
1075 }
1076
1077
1078 /**
1079  * Restart (stop and start) a GNUnet daemon.
1080  *
1081  * @param d the daemon that should be restarted
1082  * @param cb function called once the daemon is (re)started
1083  * @param cb_cls closure for cb
1084  */
1085 void
1086 GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d,
1087                                GNUNET_TESTING_NotifyDaemonRunning cb,
1088                                void *cb_cls)
1089 {
1090   char *arg;
1091   char *del_arg;
1092
1093   del_arg = NULL;
1094   if (NULL != d->cb)
1095     {
1096       d->dead = GNUNET_YES;
1097       return;
1098     }
1099
1100   d->cb = cb;
1101   d->cb_cls = cb_cls;
1102
1103   if (d->phase == SP_CONFIG_UPDATE)
1104     {
1105       GNUNET_SCHEDULER_cancel (d->task);
1106       d->phase = SP_START_DONE;
1107     }
1108   if (d->server != NULL)
1109     {
1110       GNUNET_CORE_disconnect (d->server);
1111       d->server = NULL;
1112     }
1113
1114   if (d->th != NULL)
1115     {
1116       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1117       GNUNET_TRANSPORT_disconnect (d->th);
1118       d->th = NULL;
1119     }
1120   /* state clean up and notifications */
1121   GNUNET_free_non_null (d->hello);
1122
1123 #if DEBUG_TESTING
1124   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1126 #endif
1127
1128   d->phase = SP_START_ARMING;
1129
1130   /* Check if this is a local or remote process */
1131   if (NULL != d->hostname)
1132     {
1133 #if DEBUG_TESTING
1134       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1135                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1136                   d->cfgfile, d->hostname);
1137 #endif
1138
1139       if (d->username != NULL)
1140         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1141       else
1142         arg = GNUNET_strdup (d->hostname);
1143
1144       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1145 #if !DEBUG_TESTING
1146                                          "-q",
1147 #endif
1148                                          arg, "gnunet-arm",
1149 #if DEBUG_TESTING
1150                                          "-L", "DEBUG",
1151 #endif
1152                                          "-c", d->cfgfile, "-e", "-r", NULL);
1153       /* Use -r to restart arm and all services */
1154
1155       GNUNET_free (arg);
1156     }
1157   else
1158     {
1159 #if DEBUG_TESTING
1160       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1161                   "Stopping gnunet-arm with config `%s' locally.\n",
1162                   d->cfgfile);
1163 #endif
1164       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1165                                          "gnunet-arm",
1166 #if DEBUG_TESTING
1167                                          "-L", "DEBUG",
1168 #endif
1169                                          "-c", d->cfgfile, "-e", "-r", NULL);
1170     }
1171
1172   GNUNET_free_non_null (del_arg);
1173   d->task
1174     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1175                                     &start_fsm, d);
1176
1177 }
1178
1179
1180 /**
1181  * Stops a GNUnet daemon.
1182  *
1183  * @param d the daemon that should be stopped
1184  * @param timeout how long to wait for process for shutdown to complete
1185  * @param cb function called once the daemon was stopped
1186  * @param cb_cls closure for cb
1187  * @param delete_files GNUNET_YES to remove files, GNUNET_NO
1188  *        to leave them
1189  * @param allow_restart GNUNET_YES to restart peer later (using this API)
1190  *        GNUNET_NO to kill off and clean up for good
1191  */
1192 void
1193 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
1194                             struct GNUNET_TIME_Relative timeout,
1195                             GNUNET_TESTING_NotifyCompletion cb, void *cb_cls,
1196                             int delete_files, int allow_restart)
1197 {
1198   char *arg;
1199   char *del_arg;
1200   d->dead_cb = cb;
1201   d->dead_cb_cls = cb_cls;
1202
1203   if (NULL != d->cb)
1204     {
1205 #if DEBUG_TESTING
1206       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1207                   _("Setting d->dead on peer `%4s'\n"), GNUNET_i2s (&d->id));
1208 #endif
1209       d->dead = GNUNET_YES;
1210       return;
1211     }
1212
1213   if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES))    /* Peer has already been stopped in churn context! */
1214     {
1215       /* Free what was left from churning! */
1216       GNUNET_assert (d->cfg != NULL);
1217       GNUNET_CONFIGURATION_destroy (d->cfg);
1218       if (delete_files == GNUNET_YES)
1219         {
1220           if (0 != UNLINK (d->cfgfile))
1221             {
1222               GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink");
1223             }
1224         }
1225       GNUNET_free (d->cfgfile);
1226       GNUNET_free_non_null (d->hostname);
1227       GNUNET_free_non_null (d->username);
1228       if (NULL != d->dead_cb)
1229         d->dead_cb (d->dead_cb_cls, NULL);
1230       GNUNET_free (d);
1231       return;
1232     }
1233
1234   del_arg = NULL;
1235   if (delete_files == GNUNET_YES)
1236     {
1237       GNUNET_asprintf (&del_arg, "-d");
1238     }
1239
1240   if (d->phase == SP_CONFIG_UPDATE)
1241     {
1242       GNUNET_SCHEDULER_cancel (d->task);
1243       d->phase = SP_START_DONE;
1244     }
1245   /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop?
1246   if (d->server != NULL)
1247     {
1248       GNUNET_CORE_disconnect (d->server);
1249       d->server = NULL;
1250     }
1251     */
1252   /* shutdown ARM process (will terminate others) */
1253 #if DEBUG_TESTING
1254   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1255               _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
1256 #endif
1257   d->phase = SP_SHUTDOWN_START;
1258   d->running = GNUNET_NO;
1259   if (allow_restart == GNUNET_YES)
1260     d->churn = GNUNET_YES;
1261   if (d->th != NULL)
1262     {
1263       GNUNET_TRANSPORT_get_hello_cancel (d->th, &process_hello, d);
1264       GNUNET_TRANSPORT_disconnect (d->th);
1265       d->th = NULL;
1266     }
1267   /* Check if this is a local or remote process */
1268   if (NULL != d->hostname)
1269     {
1270 #if DEBUG_TESTING
1271       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1272                   "Stopping gnunet-arm with config `%s' on host `%s'.\n",
1273                   d->cfgfile, d->hostname);
1274 #endif
1275
1276       if (d->username != NULL)
1277         GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
1278       else
1279         arg = GNUNET_strdup (d->hostname);
1280
1281       d->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
1282 #if !DEBUG_TESTING
1283                                          "-q",
1284 #endif
1285                                          arg, "gnunet-arm",
1286 #if DEBUG_TESTING
1287                                          "-L", "DEBUG",
1288 #endif
1289                                          "-c", d->cfgfile, "-e", "-q",
1290                                          del_arg, NULL);
1291       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1292                   "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n",
1293                   arg, "gnunet-arm", d->cfgfile, del_arg);
1294       /* Use -e to end arm, and -d to remove temp files */
1295       GNUNET_free (arg);
1296     }
1297   else
1298     {
1299 #if DEBUG_TESTING
1300       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301                   "Stopping gnunet-arm with config `%s' locally.\n",
1302                   d->cfgfile);
1303 #endif
1304       d->proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
1305                                          "gnunet-arm",
1306 #if DEBUG_TESTING
1307                                          "-L", "DEBUG",
1308 #endif
1309                                          "-c", d->cfgfile, "-e", "-q",
1310                                          del_arg, NULL);
1311     }
1312
1313   GNUNET_free_non_null (del_arg);
1314   d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1315   d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d);
1316 }
1317
1318
1319 /**
1320  * Changes the configuration of a GNUnet daemon.
1321  *
1322  * @param d the daemon that should be modified
1323  * @param cfg the new configuration for the daemon
1324  * @param cb function called once the configuration was changed
1325  * @param cb_cls closure for cb
1326  */
1327 void
1328 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
1329                                    struct GNUNET_CONFIGURATION_Handle *cfg,
1330                                    GNUNET_TESTING_NotifyCompletion cb,
1331                                    void *cb_cls)
1332 {
1333   char *arg;
1334
1335   if (d->phase != SP_START_DONE)
1336     {
1337       if (NULL != cb)
1338         cb (cb_cls,
1339             _
1340             ("Peer not yet running, can not change configuration at this point."));
1341       return;
1342     }
1343
1344   /* 1) write configuration to temporary file */
1345   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
1346     {
1347       if (NULL != cb)
1348         cb (cb_cls, _("Failed to write new configuration to disk."));
1349       return;
1350     }
1351
1352   /* 2) copy file to remote host (if necessary) */
1353   if (NULL == d->hostname)
1354     {
1355       /* signal success */
1356       if (NULL != cb)
1357         cb (cb_cls, NULL);
1358       return;
1359     }
1360 #if DEBUG_TESTING
1361   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1362               "Copying updated configuration file to remote host `%s'.\n",
1363               d->hostname);
1364 #endif
1365   d->phase = SP_CONFIG_UPDATE;
1366   if (NULL != d->username)
1367     GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
1368   else
1369     GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
1370   d->proc = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
1371 #if !DEBUG_TESTING
1372                                      "-q",
1373 #endif
1374                                      d->cfgfile, arg, NULL);
1375   GNUNET_free (arg);
1376   if (NULL == d->proc)
1377     {
1378       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1379                   _
1380                   ("Could not start `%s' process to copy configuration file.\n"),
1381                   "scp");
1382       if (NULL != cb)
1383         cb (cb_cls, _("Failed to copy new configuration to remote machine."));
1384       d->phase = SP_START_DONE;
1385       return;
1386     }
1387   d->update_cb = cb;
1388   d->update_cb_cls = cb_cls;
1389   d->task
1390     = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT,
1391                                     &start_fsm, d);
1392 }
1393
1394
1395 /**
1396  * Data kept for each pair of peers that we try
1397  * to connect.
1398  */
1399 struct ConnectContext
1400 {
1401   /**
1402    * Testing handle to the first daemon.
1403    */
1404   struct GNUNET_TESTING_Daemon *d1;
1405
1406   /**
1407    * Handle to core of first daemon (to check connect)
1408    */
1409   struct GNUNET_CORE_Handle *d1core;
1410
1411   /**
1412    * Have we actually connected to the core of the first daemon yet?
1413    */
1414   int d1core_ready;
1415
1416   /**
1417    * Testing handle to the second daemon.
1418    */
1419   struct GNUNET_TESTING_Daemon *d2;
1420
1421   /**
1422    * Handler for the request to core to connect to this peer.
1423    */
1424   struct GNUNET_CORE_PeerRequestHandle *connect_request_handle;
1425
1426   /**
1427    * Transport handle to the first daemon (to offer the HELLO of the second daemon to).
1428    */
1429   struct GNUNET_TRANSPORT_Handle *d1th;
1430
1431   /**
1432    * Function to call once we are done (or have timed out).
1433    */
1434   GNUNET_TESTING_NotifyConnection cb;
1435
1436   /**
1437    * Closure for "nb".
1438    */
1439   void *cb_cls;
1440
1441   /**
1442    * The relative timeout from whence this connect attempt was
1443    * started.  Allows for reconnect attempts.
1444    */
1445   struct GNUNET_TIME_Relative relative_timeout;
1446
1447   /**
1448    * Maximum number of connect attempts, will retry connection
1449    * this number of times on failures.
1450    */
1451   unsigned int connect_attempts;
1452
1453   /**
1454    * Hello timeout task
1455    */
1456   GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
1457
1458   /**
1459    * Connect timeout task
1460    */
1461   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
1462
1463   /**
1464    * When should this operation be complete (or we must trigger
1465    * a timeout).
1466    */
1467   struct GNUNET_TIME_Relative timeout_hello;
1468
1469   /**
1470    * Was the connection attempt successful?
1471    */
1472   int connected;
1473
1474   /**
1475    * When connecting, do we need to send the HELLO?
1476    */
1477   int send_hello;
1478
1479   /**
1480    * The distance between the two connected peers
1481    */
1482   uint32_t distance;
1483 };
1484
1485
1486 /** Forward declaration **/
1487 static void
1488 reattempt_daemons_connect (void *cls,
1489                            const struct GNUNET_SCHEDULER_TaskContext *tc);
1490
1491
1492 /**
1493  * Notify callback about success or failure of the attempt
1494  * to connect the two peers
1495  *
1496  * @param cls our "struct ConnectContext" (freed)
1497  * @param tc reason tells us if we succeeded or failed
1498  */
1499 static void
1500 notify_connect_result (void *cls,
1501                        const struct GNUNET_SCHEDULER_TaskContext *tc)
1502 {
1503   struct ConnectContext *ctx = cls;
1504   ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1505   if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1506     {
1507       GNUNET_SCHEDULER_cancel (ctx->hello_send_task);
1508       ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1509     }
1510
1511   if (ctx->connect_request_handle != NULL)
1512     {
1513       GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle);
1514       ctx->connect_request_handle = NULL;
1515     }
1516
1517   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1518     {
1519       if (ctx->d1th != NULL)
1520         GNUNET_TRANSPORT_disconnect (ctx->d1th);
1521       ctx->d1th = NULL;
1522       if (ctx->d1core != NULL)
1523         GNUNET_CORE_disconnect (ctx->d1core);
1524 #if CONNECT_CORE2
1525       if (ctx->d2core != NULL)
1526         GNUNET_CORE_disconnect (ctx->d2core);
1527       ctx->d2core = NULL;
1528 #endif
1529       ctx->d1core = NULL;
1530       GNUNET_free (ctx);
1531       return;
1532     }
1533
1534   if (ctx->d1th != NULL)
1535     GNUNET_TRANSPORT_disconnect (ctx->d1th);
1536   ctx->d1th = NULL;
1537   if (ctx->d1core != NULL)
1538     GNUNET_CORE_disconnect (ctx->d1core);
1539   ctx->d1core = NULL;
1540
1541   if (ctx->connected == GNUNET_YES)
1542     {
1543       if (ctx->cb != NULL)
1544         {
1545           ctx->cb (ctx->cb_cls,
1546                    &ctx->d1->id,
1547                    &ctx->d2->id,
1548                    ctx->distance,
1549                    ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
1550         }
1551     }
1552   else if (ctx->connect_attempts > 0)
1553     {
1554       ctx->d1core_ready = GNUNET_NO;
1555 #if CONNECT_CORE2
1556       if (ctx->d2core != NULL)
1557         {
1558           GNUNET_CORE_disconnect (ctx->d2core);
1559           ctx->d2core = NULL;
1560         }
1561 #endif
1562       GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx);
1563       return;
1564     }
1565   else
1566     {
1567       if (ctx->cb != NULL)
1568         {
1569           ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1570                    ctx->d2->cfg, ctx->d1, ctx->d2,
1571                    _("Peers failed to connect"));
1572         }
1573     }
1574
1575   GNUNET_free (ctx);
1576 }
1577
1578
1579 /**
1580  * Success, connection is up.  Signal client our success.
1581  *
1582  * @param cls our "struct ConnectContext"
1583  * @param peer identity of the peer that has connected
1584  * @param atsi performance information
1585  *
1586  */
1587 static void
1588 connect_notify (void *cls,
1589                 const struct GNUNET_PeerIdentity *peer,
1590                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1591 {
1592   struct ConnectContext *ctx = cls;
1593
1594 #if DEBUG_TESTING
1595   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1596                 "Connected peer %s to peer %s\n",
1597                 ctx->d1->shortname, GNUNET_i2s(peer));
1598 #endif
1599
1600   if (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))
1601     {
1602
1603       ctx->connected = GNUNET_YES;
1604       ctx->distance = 0;        /* FIXME: distance */
1605       if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
1606         {
1607           GNUNET_SCHEDULER_cancel(ctx->hello_send_task);
1608           ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1609         }
1610       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
1611       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1612                                                     ctx);
1613     }
1614 }
1615
1616 #if CONNECT_CORE2
1617 /**
1618  * Success, connection is up.  Signal client our success.
1619  *
1620  * @param cls our "struct ConnectContext"
1621  * @param peer identity of the peer that has connected
1622  * @param atsi performance information
1623  *
1624  */
1625 static void
1626 connect_notify_core2 (void *cls,
1627                       const struct GNUNET_PeerIdentity *peer,
1628                       const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1629 {
1630   struct ConnectContext *ctx = cls;
1631
1632   if (memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
1633     {
1634       ctx->connected = GNUNET_YES;
1635       ctx->distance = 0;        /* FIXME: distance */
1636       GNUNET_SCHEDULER_cancel (ctx->timeout_task);
1637       ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1638                                                     ctx);
1639     }
1640
1641 }
1642 #endif
1643
1644 /**
1645  * Task called once a core connect request has been transmitted.
1646  *
1647  * @param cls struct ConnectContext
1648  * @param success was the request successful?
1649  */
1650 void
1651 core_connect_request_cont (void *cls,
1652                            int success)
1653 {
1654   struct ConnectContext *ctx = cls;
1655
1656   ctx->connect_request_handle = NULL;
1657 }
1658
1659 static void
1660 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1661 {
1662   struct ConnectContext *ctx = cls;
1663   struct GNUNET_MessageHeader *hello;
1664   ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
1665   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1666     return;
1667   if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL)
1668       && (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)))
1669     {
1670       hello = GNUNET_HELLO_get_header (ctx->d2->hello);
1671       GNUNET_assert (hello != NULL);
1672       GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL);
1673       GNUNET_assert (ctx->d1core != NULL);
1674       ctx->connect_request_handle =
1675         GNUNET_CORE_peer_request_connect (ctx->d1core,
1676                                           ctx->relative_timeout,
1677                                           &ctx->d2->id,
1678                                           &core_connect_request_cont, ctx);
1679
1680 #if DEBUG_TESTING
1681       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1682                   "Sending connect request to CORE of %s for peer %s\n",
1683                   GNUNET_i2s (&ctx->d1->id),
1684                   GNUNET_h2s (&ctx->d2->id.hashPubKey));
1685 #endif
1686       ctx->timeout_hello =
1687         GNUNET_TIME_relative_add (ctx->timeout_hello,
1688                                   GNUNET_TIME_relative_multiply
1689                                   (GNUNET_TIME_UNIT_MILLISECONDS, 500));
1690     }
1691   ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello,
1692                                                        &send_hello, ctx);
1693 }
1694
1695 /**
1696  * Notify of a successful connection to the core service.
1697  *
1698  * @param cls a ConnectContext
1699  * @param server handle to the core service
1700  * @param my_identity the peer identity of this peer
1701  * @param publicKey the public key of the peer
1702  */
1703 void
1704 core_init_notify (void *cls,
1705                   struct GNUNET_CORE_Handle * server,
1706                   const struct GNUNET_PeerIdentity *
1707                   my_identity,
1708                   const struct
1709                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
1710                   publicKey)
1711 {
1712   struct ConnectContext *connect_ctx = cls;
1713   connect_ctx->d1core_ready = GNUNET_YES;
1714
1715   if (connect_ctx->send_hello == GNUNET_NO)
1716     {
1717       connect_ctx->connect_request_handle =
1718           GNUNET_CORE_peer_request_connect (connect_ctx->d1core,
1719                                             connect_ctx->relative_timeout,
1720                                             &connect_ctx->d2->id,
1721                                             &core_connect_request_cont, connect_ctx);
1722       GNUNET_assert(connect_ctx->connect_request_handle != NULL);
1723 #if DEBUG_TESTING
1724       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1725                   "Sending connect request to CORE of %s for peer %s\n",
1726                   connect_ctx->d1->shortname,
1727                   connect_ctx->d2->shortname);
1728 #endif
1729     }
1730
1731 }
1732
1733
1734 static void
1735 reattempt_daemons_connect (void *cls,
1736                            const struct GNUNET_SCHEDULER_TaskContext *tc)
1737 {
1738   struct ConnectContext *ctx = cls;
1739   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1740     {
1741       GNUNET_free(ctx);
1742       return;
1743     }
1744 #if DEBUG_TESTING_RECONNECT
1745   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1746               "re-attempting connect of peer %s to peer %s\n",
1747               ctx->d1->shortname, ctx->d2->shortname);
1748 #endif
1749   ctx->connect_attempts--;
1750   GNUNET_assert (ctx->d1core == NULL);
1751   ctx->d1core_ready = GNUNET_NO;
1752   ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
1753                                      ctx,
1754                                      &core_init_notify,
1755                                      &connect_notify, NULL, NULL,
1756                                      NULL, GNUNET_NO,
1757                                      NULL, GNUNET_NO, no_handlers);
1758   if (ctx->d1core == NULL)
1759     {
1760       if (NULL != ctx->cb)
1761         ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1762                  ctx->d2->cfg, ctx->d1, ctx->d2,
1763                  _("Failed to connect to core service of first peer!\n"));
1764       GNUNET_free (ctx);
1765       return;
1766     }
1767
1768   if (ctx->send_hello == GNUNET_YES)
1769     {
1770       ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
1771                                             &ctx->d1->id,
1772                                             ctx->d1, NULL, NULL, NULL);
1773       if (ctx->d1th == NULL)
1774         {
1775           GNUNET_CORE_disconnect (ctx->d1core);
1776           GNUNET_free (ctx);
1777           if (NULL != ctx->cb)
1778             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg,
1779                      ctx->d2->cfg, ctx->d1, ctx->d2,
1780                      _("Failed to connect to transport service!\n"));
1781           return;
1782         }
1783       ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
1784     }
1785   else
1786     {
1787       ctx->connect_request_handle =
1788         GNUNET_CORE_peer_request_connect (ctx->d1core,
1789                                           ctx->relative_timeout,
1790                                           &ctx->d2->id,
1791                                           &core_connect_request_cont, ctx);
1792     }
1793   ctx->timeout_task =
1794     GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
1795                                   &notify_connect_result, ctx);
1796 }
1797
1798 /**
1799  * Iterator for currently known peers, to ensure
1800  * that we don't try to send duplicate connect
1801  * requests to core.
1802  *
1803  * @param cls our "struct ConnectContext"
1804  * @param peer identity of the peer that has connected,
1805  *        NULL when iteration has finished
1806  * @param atsi performance information
1807  *
1808  */
1809 static void
1810 core_initial_iteration (void *cls,
1811                         const struct GNUNET_PeerIdentity *peer,
1812                         const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1813 {
1814   struct ConnectContext *ctx = cls;
1815
1816   if ((peer != NULL) &&
1817       (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))))
1818     {
1819       ctx->connected = GNUNET_YES;
1820       ctx->distance = 0;        /* FIXME: distance */
1821       return;
1822     }
1823   else if (peer == NULL) /* End of iteration over peers */
1824     {
1825       if (ctx->connected == GNUNET_YES)
1826         {
1827           ctx->timeout_task = GNUNET_SCHEDULER_add_now (&notify_connect_result,
1828                                                         ctx);
1829           return;
1830         }
1831
1832       /* Peer not already connected, need to schedule connect request! */
1833       if (ctx->d1core == NULL)
1834         {
1835 #if DEBUG_TESTING
1836           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1837                       "Peers are NOT connected, connecting to core!\n");
1838 #endif
1839           ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1,
1840                                              ctx,
1841                                              &core_init_notify,
1842                                              &connect_notify, NULL, NULL,
1843                                              NULL, GNUNET_NO,
1844                                              NULL, GNUNET_NO, no_handlers);
1845         }
1846
1847       if (ctx->d1core == NULL)
1848         {
1849           GNUNET_free (ctx);
1850           if (NULL != ctx->cb)
1851             ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1852                 _("Failed to connect to core service of first peer!\n"));
1853           return;
1854         }
1855
1856       if (ctx->send_hello == GNUNET_YES)
1857         {
1858           ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg,
1859                                                 &ctx->d1->id, ctx->d1, NULL, NULL, NULL);
1860           if (ctx->d1th == NULL)
1861             {
1862               GNUNET_CORE_disconnect (ctx->d1core);
1863               GNUNET_free (ctx);
1864               if (NULL != ctx->cb)
1865                 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1866                     _("Failed to connect to transport service!\n"));
1867               return;
1868             }
1869           ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx);
1870         }
1871
1872       ctx->timeout_task =
1873         GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout,
1874                                       &notify_connect_result, ctx);
1875     }
1876 }
1877
1878
1879 /**
1880  * Establish a connection between two GNUnet daemons.
1881  *
1882  * @param d1 handle for the first daemon
1883  * @param d2 handle for the second daemon
1884  * @param timeout how long is the connection attempt
1885  *        allowed to take?
1886  * @param max_connect_attempts how many times should we try to reconnect
1887  *        (within timeout)
1888  * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume
1889  *                   the HELLO has already been exchanged
1890  * @param cb function to call at the end
1891  * @param cb_cls closure for cb
1892  */
1893 void
1894 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
1895                                 struct GNUNET_TESTING_Daemon *d2,
1896                                 struct GNUNET_TIME_Relative timeout,
1897                                 unsigned int max_connect_attempts,
1898                                 int send_hello,
1899                                 GNUNET_TESTING_NotifyConnection cb,
1900                                 void *cb_cls)
1901 {
1902   struct ConnectContext *ctx;
1903
1904   if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
1905     {
1906       if (NULL != cb)
1907         cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2,
1908             _("Peers are not fully running yet, can not connect!\n"));
1909       return;
1910     }
1911
1912   ctx = GNUNET_malloc (sizeof (struct ConnectContext));
1913   ctx->d1 = d1;
1914   ctx->d2 = d2;
1915   ctx->timeout_hello =
1916     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500);
1917   ctx->relative_timeout = GNUNET_TIME_relative_divide(timeout, max_connect_attempts);
1918   ctx->cb = cb;
1919   ctx->cb_cls = cb_cls;
1920   ctx->connect_attempts = max_connect_attempts;
1921   ctx->connected = GNUNET_NO;
1922   ctx->send_hello = send_hello;
1923 #if DEBUG_TESTING
1924   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1925               "Asked to connect peer %s to peer %s\n",
1926               d1->shortname, d2->shortname);
1927 #endif
1928
1929   /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */
1930   GNUNET_assert(GNUNET_OK == GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx));
1931   /*GNUNET_assert(GNUNET_OK == GNUNET_CORE_iterate_peers (ctx->d1->cfg, &core_initial_iteration, ctx));*/
1932 }
1933
1934 /* end of testing.c */