2 This file is part of GNUnet
3 (C) 2008, 2009 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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.
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
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"
40 #define DEBUG_TESTING GNUNET_NO
41 #define DEBUG_TESTING_RECONNECT GNUNET_YES
44 * How long do we wait after starting gnunet-service-arm
45 * for the core service to be alive?
47 #define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
50 * How many times are we willing to try to wait for "scp" or
51 * "gnunet-service-arm" to complete (waitpid) before giving up?
53 #define MAX_EXEC_WAIT_RUNS 50
55 static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} };
58 * Receive the HELLO from one peer, give it to the other
59 * and ask them to connect.
61 * @param cls "struct ConnectContext"
62 * @param message HELLO message of peer
65 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
67 struct GNUNET_TESTING_Daemon *daemon = cls;
71 if (daemon->server != NULL)
73 GNUNET_CORE_disconnect(daemon->server);
74 daemon->server = NULL;
77 GNUNET_assert (message != NULL);
78 if (daemon->th != NULL)
80 GNUNET_TRANSPORT_get_hello_cancel(daemon->th, &process_hello, daemon);
83 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84 "Received `%s' from transport service of `%4s'\n",
85 "HELLO", GNUNET_i2s (&daemon->id));
88 GNUNET_free_non_null(daemon->hello);
89 daemon->hello = GNUNET_malloc(ntohs(message->size));
90 memcpy(daemon->hello, message, ntohs(message->size));
92 if (daemon->th != NULL)
94 GNUNET_TRANSPORT_disconnect(daemon->th);
101 * Function called after GNUNET_CORE_connect has succeeded
102 * (or failed for good). Note that the private key of the
103 * peer is intentionally not exposed here; if you need it,
104 * your process should try to read the private key file
105 * directly (which should work if you are authorized...).
108 * @param server handle to the server, NULL if we failed
109 * @param my_identity ID of this peer, NULL if we failed
110 * @param publicKey public key of this peer, NULL if we failed
113 testing_init (void *cls,
114 struct GNUNET_CORE_Handle *server,
115 const struct GNUNET_PeerIdentity *my_identity,
116 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
118 struct GNUNET_TESTING_Daemon *d = cls;
119 GNUNET_TESTING_NotifyDaemonRunning cb;
121 GNUNET_assert (d->phase == SP_START_CORE);
122 d->phase = SP_START_DONE;
128 if (GNUNET_YES == d->dead)
129 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
131 cb (d->cb_cls, NULL, d->cfg, d,
132 _("Failed to connect to core service\n"));
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137 "Successfully started peer `%4s'.\n", GNUNET_i2s (my_identity));
139 d->id = *my_identity;
140 d->shortname = strdup (GNUNET_i2s (my_identity));
142 d->running = GNUNET_YES;
143 if (GNUNET_YES == d->dead)
144 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
146 cb (d->cb_cls, my_identity, d->cfg, d, NULL);
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149 "Successfully started peer `%4s'.\n", GNUNET_i2s (my_identity));
153 d->th = GNUNET_TRANSPORT_connect (d->sched,
154 d->cfg, d, NULL, NULL, NULL);
157 if (GNUNET_YES == d->dead)
158 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
159 else if (NULL != d->cb)
160 d->cb (d->cb_cls, &d->id, d->cfg, d,
161 _("Failed to connect to transport service!\n"));
165 GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d);
170 * Finite-state machine for starting GNUnet.
172 * @param cls our "struct GNUNET_TESTING_Daemon"
176 start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
178 struct GNUNET_TESTING_Daemon *d = cls;
179 GNUNET_TESTING_NotifyDaemonRunning cb;
180 enum GNUNET_OS_ProcessStatusType type;
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "Peer FSM is in phase %u.\n", d->phase);
189 d->task = GNUNET_SCHEDULER_NO_TASK;
193 /* confirm copying complete */
194 if (GNUNET_OK != GNUNET_OS_process_status (d->pid, &type, &code))
197 if (d->wait_runs > MAX_EXEC_WAIT_RUNS)
204 d->cfg, d, _("`scp' does not seem to terminate.\n"));
209 = GNUNET_SCHEDULER_add_delayed (d->sched,
210 GNUNET_CONSTANTS_EXEC_WAIT,
214 if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
220 NULL, d->cfg, d, _("`scp' did not complete cleanly.\n"));
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Successfully copied configuration file.\n");
227 d->phase = SP_COPIED;
230 /* start GNUnet on remote host */
231 if (NULL == d->hostname)
234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
235 "Starting `%s', with command `%s %s %s %s %s %s'.\n",
236 "gnunet-arm", "gnunet-arm", "-c", d->cfgfile,
240 d->pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
250 if (d->username != NULL)
251 GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname);
253 dst = GNUNET_strdup (d->hostname);
256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
257 "Starting `%s', with command `%s %s %s %s %s %s %s %s'.\n",
258 "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile,
259 "-L", "DEBUG", "-s", "-q");
261 d->pid = GNUNET_OS_start_process (NULL, NULL, "ssh",
268 "-c", d->cfgfile, "-s", "-q", NULL);
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 _("Could not start `%s' process to start GNUnet.\n"),
275 (NULL == d->hostname) ? "gnunet-arm" : "ssh");
283 (NULL == d->hostname)
284 ? _("Failed to start `gnunet-arm' process.\n")
285 : _("Failed to start `ssh' process.\n"));
288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289 "Started `%s', waiting for `%s' to be up.\n",
290 "gnunet-arm", "gnunet-service-core");
292 d->phase = SP_START_ARMING;
295 = GNUNET_SCHEDULER_add_delayed (d->sched,
296 GNUNET_CONSTANTS_EXEC_WAIT,
299 case SP_START_ARMING:
300 if (GNUNET_OK != GNUNET_OS_process_status (d->pid, &type, &code))
303 if (d->wait_runs > MAX_EXEC_WAIT_RUNS)
312 (NULL == d->hostname)
313 ? _("`gnunet-arm' does not seem to terminate.\n")
314 : _("`ssh' does not seem to terminate.\n"));
319 = GNUNET_SCHEDULER_add_delayed (d->sched,
320 GNUNET_CONSTANTS_EXEC_WAIT,
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326 "Successfully started `%s'.\n", "gnunet-arm");
328 d->phase = SP_START_CORE;
329 d->server = GNUNET_CORE_connect (d->sched,
336 NULL, GNUNET_NO, no_handlers);
344 case SP_SHUTDOWN_START:
345 /* confirm copying complete */
346 if (GNUNET_OK != GNUNET_OS_process_status (d->pid, &type, &code))
349 if (d->wait_runs > MAX_EXEC_WAIT_RUNS)
351 d->dead_cb (d->dead_cb_cls,
352 _("either `gnunet-arm' or `ssh' does not seem to terminate.\n"));
355 GNUNET_TRANSPORT_get_hello_cancel(d->th, &process_hello, d);
356 GNUNET_TRANSPORT_disconnect(d->th);
359 GNUNET_CONFIGURATION_destroy (d->cfg);
360 GNUNET_free (d->cfgfile);
361 GNUNET_free_non_null(d->hello);
362 GNUNET_free_non_null (d->hostname);
363 GNUNET_free_non_null (d->username);
364 GNUNET_free_non_null (d->shortname);
370 = GNUNET_SCHEDULER_add_delayed (d->sched,
371 GNUNET_CONSTANTS_EXEC_WAIT,
375 if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
377 if (NULL != d->dead_cb)
378 d->dead_cb (d->dead_cb_cls,
379 _("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n"));
382 GNUNET_TRANSPORT_get_hello_cancel(d->th, &process_hello, d);
383 GNUNET_TRANSPORT_disconnect(d->th);
386 GNUNET_CONFIGURATION_destroy (d->cfg);
387 GNUNET_free (d->cfgfile);
388 GNUNET_free_non_null(d->hello);
389 GNUNET_free_non_null (d->hostname);
390 GNUNET_free_non_null (d->username);
391 GNUNET_free_non_null (d->shortname);
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n");
400 GNUNET_TRANSPORT_get_hello_cancel(d->th, &process_hello, d);
401 GNUNET_TRANSPORT_disconnect(d->th);
404 /* state clean up and notifications */
405 GNUNET_CONFIGURATION_destroy (d->cfg);
406 GNUNET_free (d->cfgfile);
407 GNUNET_free_non_null(d->hello);
408 GNUNET_free_non_null (d->hostname);
409 GNUNET_free_non_null (d->username);
410 GNUNET_free_non_null (d->shortname);
411 if (NULL != d->dead_cb)
412 d->dead_cb (d->dead_cb_cls, NULL);
415 case SP_CONFIG_UPDATE:
416 /* confirm copying complete */
417 if (GNUNET_OK != GNUNET_OS_process_status (d->pid, &type, &code))
420 if (d->wait_runs > MAX_EXEC_WAIT_RUNS)
427 d->cfg, d, _("`scp' does not seem to terminate.\n"));
432 = GNUNET_SCHEDULER_add_delayed (d->sched,
433 GNUNET_CONSTANTS_EXEC_WAIT,
437 if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
439 if (NULL != d->update_cb)
440 d->update_cb (d->update_cb_cls,
441 _("`scp' did not complete cleanly.\n"));
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446 "Successfully copied configuration file.\n");
448 if (NULL != d->update_cb)
449 d->update_cb (d->update_cb_cls, NULL);
450 d->phase = SP_START_DONE;
457 * Starts a GNUnet daemon. GNUnet must be installed on the target
458 * system and available in the PATH. The machine must furthermore be
459 * reachable via "ssh" (unless the hostname is "NULL") without the
460 * need to enter a password.
462 * @param sched scheduler to use
463 * @param cfg configuration to use
464 * @param hostname name of the machine where to run GNUnet
465 * (use NULL for localhost).
466 * @param cb function to call with the result
467 * @param cb_cls closure for cb
468 * @return handle to the daemon (actual start will be completed asynchronously)
470 struct GNUNET_TESTING_Daemon *
471 GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
472 const struct GNUNET_CONFIGURATION_Handle *cfg,
473 const char *hostname,
474 GNUNET_TESTING_NotifyDaemonRunning cb,
477 struct GNUNET_TESTING_Daemon *ret;
481 ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon));
483 ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
484 ret->cfgfile = GNUNET_DISK_mktemp ("gnunet-testing-config");
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Setting up peer with configuration file `%s'.\n",
490 if (NULL == ret->cfgfile)
492 GNUNET_free_non_null (ret->hostname);
497 ret->cb_cls = cb_cls;
498 ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
499 GNUNET_CONFIGURATION_set_value_string (ret->cfg,
501 "DEFAULTCONFIG", ret->cfgfile);
502 /* 1) write configuration to temporary file */
503 if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile))
505 if (0 != UNLINK (ret->cfgfile))
506 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
507 "unlink", ret->cfgfile);
508 GNUNET_CONFIGURATION_destroy (ret->cfg);
509 GNUNET_free_non_null (ret->hostname);
510 GNUNET_free (ret->cfgfile);
515 GNUNET_CONFIGURATION_get_value_string (cfg,
517 "USERNAME", &username))
519 if (NULL != getenv ("USER"))
520 username = GNUNET_strdup (getenv ("USER"));
524 ret->username = username;
526 /* 2) copy file to remote host */
527 if (NULL != hostname)
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531 "Copying configuration file to host `%s'.\n", hostname);
533 ret->phase = SP_COPYING;
534 if (NULL != username)
535 GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, ret->cfgfile);
537 GNUNET_asprintf (&arg, "%s:%s", hostname, ret->cfgfile);
538 ret->pid = GNUNET_OS_start_process (NULL, NULL, "scp",
539 "scp", ret->cfgfile, arg, NULL);
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545 ("Could not start `%s' process to copy configuration file.\n"),
547 if (0 != UNLINK (ret->cfgfile))
548 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
549 "unlink", ret->cfgfile);
550 GNUNET_CONFIGURATION_destroy (ret->cfg);
551 GNUNET_free_non_null (ret->hostname);
552 GNUNET_free_non_null (ret->username);
553 GNUNET_free (ret->cfgfile);
558 = GNUNET_SCHEDULER_add_delayed (sched,
559 GNUNET_CONSTANTS_EXEC_WAIT,
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 "No need to copy configuration file since we are running locally.\n");
567 ret->phase = SP_COPIED;
568 GNUNET_SCHEDULER_add_continuation (sched,
571 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
577 * Stops a GNUnet daemon.
579 * @param d the daemon that should be stopped
580 * @param cb function called once the daemon was stopped
581 * @param cb_cls closure for cb
584 GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
585 GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
590 d->dead_cb_cls = cb_cls;
594 d->dead = GNUNET_YES;
597 if (d->phase == SP_CONFIG_UPDATE)
599 GNUNET_SCHEDULER_cancel (d->sched, d->task);
600 d->phase = SP_START_DONE;
602 if (d->server != NULL)
604 GNUNET_CORE_disconnect (d->server);
607 /* shutdown ARM process (will terminate others) */
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id));
611 /* sleep(15); Manual check for running */
614 d->phase = SP_SHUTDOWN_START;
616 /* Check if this is a local or remote process */
617 if (NULL != d->hostname)
620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
621 "Stopping gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname);
624 if (d->username != NULL)
625 GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname);
627 arg = GNUNET_strdup (d->hostname);
629 d->pid = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh",
634 "-c", d->cfgfile, "-e", "-d", "-q", NULL);
635 /* Use -e to end arm, and -d to remove temp files */
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile);
645 d->pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
650 "-c", d->cfgfile, "-e", "-d", "-q", NULL);
655 = GNUNET_SCHEDULER_add_delayed (d->sched,
656 GNUNET_CONSTANTS_EXEC_WAIT,
662 * Changes the configuration of a GNUnet daemon.
664 * @param d the daemon that should be modified
665 * @param cfg the new configuration for the daemon
666 * @param cb function called once the configuration was changed
667 * @param cb_cls closure for cb
670 GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
671 struct GNUNET_CONFIGURATION_Handle *cfg,
672 GNUNET_TESTING_NotifyCompletion cb,
677 if (d->phase != SP_START_DONE)
682 ("Peer not yet running, can not change configuration at this point."));
686 /* 1) write configuration to temporary file */
687 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile))
690 cb (cb_cls, _("Failed to write new configuration to disk."));
694 /* 2) copy file to remote host (if necessary) */
695 if (NULL == d->hostname)
703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704 "Copying updated configuration file to remote host `%s'.\n",
707 d->phase = SP_CONFIG_UPDATE;
708 if (NULL != d->username)
709 GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile);
711 GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile);
712 d->pid = GNUNET_OS_start_process (NULL, NULL, "scp", "scp", d->cfgfile, arg, NULL);
716 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
718 ("Could not start `%s' process to copy configuration file.\n"),
721 cb (cb_cls, _("Failed to copy new configuration to remote machine."));
722 d->phase = SP_START_DONE;
726 d->update_cb_cls = cb_cls;
728 = GNUNET_SCHEDULER_add_delayed (d->sched,
729 GNUNET_CONSTANTS_EXEC_WAIT,
735 * Data kept for each pair of peers that we try
738 struct ConnectContext
741 * Testing handle to the first daemon.
743 struct GNUNET_TESTING_Daemon *d1;
746 * Handle to core of first daemon (to check connect)
748 struct GNUNET_CORE_Handle * d1core;
751 * Testing handle to the second daemon.
753 struct GNUNET_TESTING_Daemon *d2;
756 * Transport handle to the second daemon.
758 struct GNUNET_TRANSPORT_Handle *d2th;
761 * Function to call once we are done (or have timed out).
763 GNUNET_TESTING_NotifyConnection cb;
771 * When should this operation be complete (or we must trigger
774 struct GNUNET_TIME_Absolute timeout;
777 * The relative timeout from whence this connect attempt was
778 * started. Allows for reconnect attempts.
780 struct GNUNET_TIME_Relative relative_timeout;
783 * Maximum number of connect attempts, will retry connection
784 * this number of times on failures.
786 unsigned int max_connect_attempts;
791 GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
794 * Connect timeout task
796 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
799 * When should this operation be complete (or we must trigger
802 struct GNUNET_TIME_Relative timeout_hello;
806 * Was the connection attempt successful?
812 /** Forward declaration **/
814 reattempt_daemons_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
818 * Notify callback about success or failure of the attempt
819 * to connect the two peers
821 * @param cls our "struct ConnectContext" (freed)
822 * @param tc reason tells us if we succeeded or failed
825 notify_connect_result (void *cls,
826 const struct GNUNET_SCHEDULER_TaskContext *tc)
828 struct ConnectContext *ctx = cls;
829 struct GNUNET_TIME_Relative remaining;
831 if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK)
833 GNUNET_SCHEDULER_cancel(ctx->d1->sched, ctx->hello_send_task);
834 ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK;
837 if ((ctx->timeout_task != GNUNET_SCHEDULER_NO_TASK) && (tc->reason != GNUNET_SCHEDULER_REASON_TIMEOUT))
839 GNUNET_SCHEDULER_cancel(ctx->d1->sched, ctx->timeout_task);
840 ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
843 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
845 if (ctx->d2th != NULL)
846 GNUNET_TRANSPORT_disconnect (ctx->d2th);
848 if (ctx->d1core != NULL)
849 GNUNET_CORE_disconnect (ctx->d1core);
856 remaining = GNUNET_TIME_absolute_get_remaining(ctx->timeout);
858 if (ctx->connected == GNUNET_YES)
862 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
863 ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
866 else if (remaining.value > 0)
868 if (ctx->d1core != NULL)
870 GNUNET_CORE_disconnect(ctx->d1core);
874 if (ctx->d2th != NULL)
876 GNUNET_TRANSPORT_disconnect(ctx->d2th);
879 GNUNET_SCHEDULER_add_now(ctx->d1->sched, &reattempt_daemons_connect, ctx);
886 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
887 ctx->d2->cfg, ctx->d1, ctx->d2,
888 _("Peers failed to connect"));
892 GNUNET_TRANSPORT_disconnect (ctx->d2th);
894 GNUNET_CORE_disconnect (ctx->d1core);
901 * Success, connection is up. Signal client our success.
903 * @param cls our "struct ConnectContext"
904 * @param peer identity of the peer that has connected
905 * @param latency the round trip latency of the connection to this peer
906 * @param distance distance the transport level distance to this peer
910 connect_notify (void *cls, const struct GNUNET_PeerIdentity * peer, struct GNUNET_TIME_Relative latency,
913 struct ConnectContext *ctx = cls;
915 if (memcmp(&ctx->d2->id, peer, sizeof(struct GNUNET_PeerIdentity)) == 0)
917 ctx->connected = GNUNET_YES;
918 GNUNET_SCHEDULER_cancel(ctx->d1->sched, ctx->timeout_task);
919 ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
920 GNUNET_SCHEDULER_add_now (ctx->d1->sched,
921 ¬ify_connect_result,
928 send_hello(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
930 struct ConnectContext *ctx = cls;
932 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
935 if (ctx->d1->hello != NULL)
937 GNUNET_TRANSPORT_offer_hello (ctx->d2th, GNUNET_HELLO_get_header(ctx->d1->hello));
938 ctx->timeout_hello = GNUNET_TIME_relative_add(ctx->timeout_hello,
939 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS,
942 ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed(ctx->d1->sched,
948 * Establish a connection between two GNUnet daemons.
950 * @param d1 handle for the first daemon
951 * @param d2 handle for the second daemon
952 * @param timeout how long is the connection attempt
954 * @param max_connect_attempts how many times should we try to reconnect
956 * @param cb function to call at the end
957 * @param cb_cls closure for cb
960 GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
961 struct GNUNET_TESTING_Daemon *d2,
962 struct GNUNET_TIME_Relative timeout,
963 unsigned int max_connect_attempts,
964 GNUNET_TESTING_NotifyConnection cb,
967 struct ConnectContext *ctx;
969 if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO))
972 cb (cb_cls, &d1->id, &d2->id, d1->cfg, d2->cfg, d1, d2,
973 _("Peers are not fully running yet, can not connect!\n"));
976 ctx = GNUNET_malloc (sizeof (struct ConnectContext));
979 ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
980 ctx->timeout_hello = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500);
981 ctx->relative_timeout = timeout;
983 ctx->cb_cls = cb_cls;
984 ctx->max_connect_attempts = max_connect_attempts;
985 ctx->connected = GNUNET_NO;
987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988 "Asked to connect peer %s to peer %s\n",
989 d1->shortname, d2->shortname);
992 ctx->d1core = GNUNET_CORE_connect (d1->sched,
997 &connect_notify, NULL,
999 NULL, GNUNET_NO, no_handlers);
1000 if (ctx->d1core == NULL)
1004 cb (cb_cls, &d1->id, &d2->id, d1->cfg, d2->cfg, d1, d2,
1005 _("Failed to connect to core service of first peer!\n"));
1009 #if DEBUG_TESTING > 2
1010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1011 "Asked to connect peer %s to peer %s\n",
1012 d1->shortname, d2->shortname);
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Connecting to transport service of peer %s\n", d2->shortname);
1018 ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched,
1019 d2->cfg, d2, NULL, NULL, NULL);
1020 if (ctx->d2th == NULL)
1022 GNUNET_CORE_disconnect(ctx->d1core);
1025 cb (cb_cls, &d1->id, &d2->id, d1->cfg, d2->cfg, d1, d2,
1026 _("Failed to connect to transport service!\n"));
1030 ctx->timeout_task = GNUNET_SCHEDULER_add_delayed (d1->sched,
1031 GNUNET_TIME_relative_divide(ctx->relative_timeout, max_connect_attempts), /* Allow up to 8 reconnect attempts */
1032 ¬ify_connect_result, ctx);
1034 ctx->hello_send_task = GNUNET_SCHEDULER_add_now(ctx->d1->sched, &send_hello, ctx);
1038 reattempt_daemons_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1041 struct ConnectContext *ctx = cls;
1042 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1046 #if DEBUG_TESTING_RECONNECT
1047 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "re-attempting connect of peer %s to peer %s\n",
1048 ctx->d1->shortname, ctx->d2->shortname);
1051 GNUNET_assert(ctx->d1core == NULL);
1053 ctx->d1core = GNUNET_CORE_connect (ctx->d1->sched,
1055 GNUNET_TIME_absolute_get_remaining(ctx->timeout),
1058 &connect_notify, NULL,
1060 NULL, GNUNET_NO, no_handlers);
1061 if (ctx->d1core == NULL)
1063 if (NULL != ctx->cb)
1064 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1065 _("Failed to connect to core service of first peer!\n"));
1070 ctx->d2th = GNUNET_TRANSPORT_connect (ctx->d2->sched,
1071 ctx->d2->cfg, ctx->d2, NULL, NULL, NULL);
1072 if (ctx->d2th == NULL)
1074 GNUNET_CORE_disconnect(ctx->d1core);
1076 if (NULL != ctx->cb)
1077 ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2,
1078 _("Failed to connect to transport service!\n"));
1082 ctx->timeout_task = GNUNET_SCHEDULER_add_delayed (ctx->d1->sched,
1083 GNUNET_TIME_relative_divide(ctx->relative_timeout, ctx->max_connect_attempts),
1084 ¬ify_connect_result, ctx);
1086 ctx->hello_send_task = GNUNET_SCHEDULER_add_now(ctx->d1->sched, &send_hello, ctx);
1089 /* end of testing.c */