2 This file is part of GNUnet.
3 (C) 2006, 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 transport-testing.c
23 * @brief testing lib for transport service
25 * @author Matthias Wachs
28 #include "transport-testing.h"
31 static struct PeerContext *
32 find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
33 const struct GNUNET_PeerIdentity *peer)
35 GNUNET_assert (tth != NULL);
36 struct PeerContext *t = tth->p_head;
40 if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity)))
49 static struct ConnectingContext *
50 find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
51 struct PeerContext *p1, struct PeerContext *p2)
53 GNUNET_assert (tth != NULL);
54 struct ConnectingContext *cc = tth->cc_head;
58 if ((cc->p1 == p1) && (cc->p2 == p2))
60 if ((cc->p1 == p2) && (cc->p2 == p1))
70 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
71 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
73 struct PeerContext *p = cls;
75 struct PeerContext *p2;
77 GNUNET_assert (NULL != p);
78 GNUNET_assert (NULL != p->tth);
79 p2 = find_peer_context (p->tth, peer);
81 p->nc (p->cb_cls, peer, ats, ats_count);
84 GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
86 GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
87 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
88 "Peers %s connected to peer %u (`%s')\n", p2_s, p->no,
92 /* Find ConnectingContext */
93 struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2);
99 cc->p1_c = GNUNET_YES;
102 cc->p2_c = GNUNET_YES;
104 if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
106 cc->cb (cc->p1, cc->p2, cc->cb_cls);
107 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc);
113 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
115 struct PeerContext *p = cls;
117 /* Find PeerContext */
119 struct PeerContext *p2 = NULL;
123 GNUNET_assert (p->tth != NULL);
124 p2 = find_peer_context (p->tth, peer);
131 GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
133 GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
134 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
135 "Peers %s disconnected from peer %u (`%s')\n", p2_s, no,
136 GNUNET_i2s (&p->id));
142 p->nd (p->cb_cls, peer);
147 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
148 const struct GNUNET_MessageHeader *message,
149 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
151 struct PeerContext *p = cls;
156 p->rec (p->cb_cls, peer, message, ats, ats_count);
161 get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
163 struct PeerContext *p = cb_cls;
164 struct GNUNET_PeerIdentity hello_id;
166 GNUNET_assert (message != NULL);
167 GNUNET_assert (GNUNET_OK ==
168 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
169 message, &hello_id));
170 GNUNET_assert (0 == memcmp (&hello_id, &p->id, sizeof (hello_id)));
171 GNUNET_free_non_null (p->hello);
172 p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
174 if (NULL != p->start_cb)
176 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
177 "Peer %u (`%s') successfully started\n", p->no,
178 GNUNET_i2s (&p->id));
179 p->start_cb (p, p->cb_cls);
186 try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
188 struct ConnectingContext *cc = cls;
189 struct PeerContext *p1 = cc->p1;
190 struct PeerContext *p2 = cc->p2;
192 cc->tct = GNUNET_SCHEDULER_NO_TASK;
193 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
196 GNUNET_assert (cc != NULL);
197 GNUNET_assert (cc->p1 != NULL);
198 GNUNET_assert (cc->p2 != NULL);
200 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
202 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
203 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
204 p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s,
205 GNUNET_HELLO_size (cc->p2->hello));
208 GNUNET_TRANSPORT_offer_hello (cc->th_p1,
209 (const struct GNUNET_MessageHeader *) cc->
210 p2->hello, NULL, NULL);
211 GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id);
214 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
219 * Start a peer with the given configuration
220 * @param tth the testing handle
221 * @param cfgname configuration file
222 * @param peer_id a unique number to identify the peer
223 * @param rec receive callback
224 * @param nc connect callback
225 * @param nd disconnect callback
226 * @param start_cb start callback
227 * @param cb_cls closure for callback
228 * @return the peer context
231 GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
232 const char *cfgname, int peer_id,
233 GNUNET_TRANSPORT_ReceiveCallback rec,
234 GNUNET_TRANSPORT_NotifyConnect nc,
235 GNUNET_TRANSPORT_NotifyDisconnect nd,
236 GNUNET_TRANSPORT_TESTING_start_cb start_cb,
240 struct GNUNET_PeerIdentity *dummy;
242 GNUNET_assert (NULL != tth);
243 GNUNET_assert (NULL != tth->tl_system);
245 if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
247 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
248 "File not found: `%s' \n", cfgname);
252 struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
253 GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p);
255 /* Create configuration and call testing lib to modify it */
256 p->cfg = GNUNET_CONFIGURATION_create ();
257 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
259 if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg))
261 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
262 "Testing library failed to create unique configuration based on `%s'\n",
269 /* Configure peer with configuration */
270 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system, p->cfg, p->no, NULL, &emsg);
273 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
274 "Testing library failed to create unique configuration based on `%s': `%s'\n",
276 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
277 GNUNET_free_non_null (emsg);
280 GNUNET_free_non_null (emsg);
281 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
283 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
284 "Testing library failed to create unique configuration based on `%s'\n",
286 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
290 memset(&dummy, '\0', sizeof (dummy));
291 GNUNET_TESTING_peer_get_identity (p->peer, &p->id);
292 if (0 == memcmp (&dummy, &p->id, sizeof (struct GNUNET_PeerIdentity)))
294 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
295 "Testing library failed to obtain peer identity for peer %u\n",
297 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
302 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
303 "Peer %u configured with identity `%s'\n",
305 GNUNET_i2s (&p->id));
312 p->start_cb = start_cb;
318 p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
320 ¬ify_connect, ¬ify_disconnect);
323 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
324 "Failed to connect to transport service for peer `%s': `%s'\n",
326 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
330 p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
331 GNUNET_assert (p->ghh != NULL);
337 * Restart the given peer
338 * @param tth testing handle
340 * @param cfgname the cfg file used to restart
341 * @param restart_cb callback to call when restarted
342 * @param cb_cls callback closure
343 * @return GNUNET_OK in success otherwise GNUNET_SYSERR
346 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
347 *tth, struct PeerContext *p,
349 GNUNET_TRANSPORT_TESTING_start_cb
350 restart_cb, void *cb_cls)
352 GNUNET_assert (tth != NULL);
353 GNUNET_assert (p != NULL);
354 GNUNET_assert (NULL != p->peer);
356 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
357 "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
360 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
361 "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
363 GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
367 GNUNET_TRANSPORT_disconnect (p->th);
369 if (GNUNET_SYSERR == GNUNET_TESTING_peer_stop(p->peer))
371 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
372 "Failed to stop peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
373 return GNUNET_SYSERR;
379 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start(p->peer))
381 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
382 "Failed to restart peer %u (`%s')\n",
383 p->no, GNUNET_i2s (&p->id));
384 return GNUNET_SYSERR;
387 GNUNET_assert (p->th != NULL);
388 GNUNET_assert (p->start_cb == NULL);
389 p->start_cb = restart_cb;
392 p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
396 GNUNET_assert (NULL != p->th);
398 p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
399 GNUNET_assert (p->ghh != NULL);
405 * shutdown the given peer
406 * @param tth testing handle
410 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
411 struct PeerContext *p)
413 GNUNET_assert (p != NULL);
416 GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
421 GNUNET_TRANSPORT_disconnect (p->th);
427 if (GNUNET_OK != GNUNET_TESTING_peer_stop (p->peer))
429 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
430 "Testing lib failed to stop peer %u (`%s') \n", p->no,
431 GNUNET_i2s (&p->id));
433 GNUNET_TESTING_peer_destroy (p->peer);
437 if (p->hello != NULL)
439 GNUNET_free (p->hello);
444 GNUNET_CONFIGURATION_destroy (p->cfg);
447 GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p);
448 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
449 "Peer %u (`%s') stopped \n", p->no,
450 GNUNET_i2s (&p->id));
456 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
458 * Remarks: start_peer's notify_connect callback can be called before.
460 * @param tth transport testing handle
463 * @param cb the callback to call when both peers notified that they are connected
464 * @param cls callback cls
465 * @return a connect request handle
467 GNUNET_TRANSPORT_TESTING_ConnectRequest
468 GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
469 struct PeerContext *p1,
470 struct PeerContext *p2,
471 GNUNET_TRANSPORT_TESTING_connect_cb cb,
474 GNUNET_assert (tth != NULL);
476 struct ConnectingContext *cc =
477 GNUNET_malloc (sizeof (struct ConnectingContext));
479 GNUNET_assert (p1 != NULL);
480 GNUNET_assert (p2 != NULL);
490 GNUNET_assert (cc->th_p1 != NULL);
491 GNUNET_assert (cc->th_p2 != NULL);
492 GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc);
493 cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
494 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
495 "New connect request %p\n", cc);
502 * Cancel the request to connect two peers
503 * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
505 * @param tth transport testing handle
506 * @param ccr a connect request handle
509 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
510 GNUNET_TRANSPORT_TESTING_handle
512 GNUNET_TRANSPORT_TESTING_ConnectRequest
515 struct ConnectingContext *cc = ccr;
517 GNUNET_assert (tth != NULL);
519 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
520 "Canceling connect request %p!\n", cc);
522 if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
523 GNUNET_SCHEDULER_cancel (cc->tct);
524 cc->tct = GNUNET_SCHEDULER_NO_TASK;
526 GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc);
532 * Clean up the transport testing
533 * @param tth transport testing handle
536 GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth)
538 struct ConnectingContext *cc = tth->cc_head;
539 struct ConnectingContext *ct = NULL;
540 struct PeerContext *p = tth->p_head;
541 struct PeerContext *t = NULL;
543 GNUNET_assert (tth != NULL);
545 while (cc != tth->cc_tail)
548 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
549 "Developer forgot to cancel connect request %p!\n", cc);
550 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
557 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
558 "Developer forgot to stop peer!\n");
559 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
563 GNUNET_TESTING_system_destroy (tth->tl_system, GNUNET_YES);
571 * Initialize the transport testing
572 * @return transport testing handle
574 struct GNUNET_TRANSPORT_TESTING_handle *
575 GNUNET_TRANSPORT_TESTING_init ()
577 struct GNUNET_TRANSPORT_TESTING_handle *tth;
579 /* prepare hostkeys */
580 tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle));
582 /* Init testing the testing lib */
583 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing", NULL, NULL);
584 if (NULL == tth->tl_system)
586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize testing library!\n"));
596 * Some utility functions
600 * Removes all directory separators from absolute filename
601 * @param file the absolute file name, e.g. as found in argv[0]
602 * @return extracted file name, has to be freed by caller
605 extract_filename (const char *file)
607 char *pch = GNUNET_strdup (file);
609 char *filename = NULL;
612 if ((strlen (pch) >= 3) && pch[1] == ':')
614 if (NULL != strstr (pch, "\\"))
616 pch = strtok (pch, "\\");
619 pch = strtok (NULL, "\\");
625 if (filename != NULL)
626 pch = filename; /* If we miss the next condition, filename = pch will
630 if (NULL != strstr (pch, "/"))
632 pch = strtok (pch, "/");
635 pch = strtok (NULL, "/");
645 res = GNUNET_strdup (filename);
646 GNUNET_free (backup);
652 * Extracts the test filename from an absolute file name and removes the extension
653 * @param file absolute file name
654 * @param dest where to store result
657 GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest)
659 char *filename = extract_filename (file);
660 char *backup = filename;
663 if (filename == NULL)
667 filename = strstr (filename, "tes");
668 if (filename == NULL)
672 if (NULL != (dotexe = strstr (filename, ".exe")))
682 /* create filename */
683 GNUNET_asprintf (dest, "%s", filename);
684 GNUNET_free (backup);
689 * Extracts the filename from an absolute file name and removes the extension
690 * @param file absolute file name
691 * @param dest where to store result
694 GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest)
696 char *src = extract_filename (file);
699 split = strstr (src, ".");
704 GNUNET_asprintf (dest, "%s", src);
710 * Extracts the plugin name from an absolute file name and the test name
712 * @param file absolute file name
713 * @param test test name
714 * @param dest where to store result
717 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
718 const char *test, char **dest)
722 char *e = extract_filename (file);
723 char *t = extract_filename (test);
728 filename = strstr (e, "tes");
729 if (NULL == filename)
732 if (NULL != (dotexe = strstr (filename, ".exe")))
736 filename = strstr (filename, t);
737 if (NULL == filename)
740 filename += strlen (t);
741 if ('\0' != *filename)
743 GNUNET_asprintf (dest, "%s", filename);
754 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
755 * if existing ".exe"-prefix and adds the peer-number
757 * @param file filename of the test, e.g. argv[0]
758 * @param dest where to write the filename
759 * @param count peer number
762 GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
765 char *filename = extract_filename (file);
766 char *backup = filename;
769 if (NULL == filename)
772 filename = strstr (filename, "tes");
773 if (NULL == filename)
776 if (NULL != (dotexe = strstr (filename, ".exe")))
778 GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count);
779 GNUNET_free (backup);
783 GNUNET_free (backup);
787 /* end of transport-testing.c */