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"
30 struct ConnectingContext
32 struct PeerContext *p1;
33 struct PeerContext *p2;
34 GNUNET_SCHEDULER_TaskIdentifier tct;
35 GNUNET_TRANSPORT_TESTING_connect_cb cb;
37 struct GNUNET_TRANSPORT_Handle *th_p1;
38 struct GNUNET_TRANSPORT_Handle *th_p2;
44 exchange_hello_last (void *cb_cls, const struct GNUNET_MessageHeader *message);
46 exchange_hello (void *cb_cls, const struct GNUNET_MessageHeader *message);
49 notify_connect_internal (void *cls, const struct GNUNET_PeerIdentity *peer,
50 const struct GNUNET_TRANSPORT_ATS_Information *ats,
53 struct ConnectingContext *cc = cls;
55 GNUNET_assert (cc != NULL);
58 memcmp (&(*peer).hashPubKey, &cc->p1->id.hashPubKey,
59 sizeof (GNUNET_HashCode)))
61 if (cc->p1_c == GNUNET_NO)
62 cc->p1_c = GNUNET_YES;
65 memcmp (&(*peer).hashPubKey, &cc->p2->id.hashPubKey,
66 sizeof (GNUNET_HashCode)))
68 if (cc->p2_c == GNUNET_NO)
69 cc->p2_c = GNUNET_YES;
72 if ((cc->p2_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
75 GNUNET_TRANSPORT_get_hello_cancel (cc->p1->ghh);
76 GNUNET_TRANSPORT_get_hello_cancel (cc->p2->ghh);
78 if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
79 GNUNET_SCHEDULER_cancel (cc->tct);
81 cc->tct = GNUNET_SCHEDULER_NO_TASK;
83 GNUNET_TRANSPORT_disconnect (cc->th_p1);
84 GNUNET_TRANSPORT_disconnect (cc->th_p2);
87 cc->cb (cc->p1, cc->p2, cc->cb_cls);
94 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
95 const struct GNUNET_TRANSPORT_ATS_Information *ats,
98 struct PeerContext *p = cls;
103 p->nc (p->cb_cls, peer, ats, ats_count);
107 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
109 struct PeerContext *p = cls;
114 p->nd (p->cb_cls, peer);
118 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
119 const struct GNUNET_MessageHeader *message,
120 const struct GNUNET_TRANSPORT_ATS_Information *ats,
123 struct PeerContext *p = cls;
128 p->rec (p->cb_cls, peer, message, ats, ats_count);
133 exchange_hello_last (void *cb_cls, const struct GNUNET_MessageHeader *message)
135 struct ConnectingContext *cc = cb_cls;
136 struct PeerContext *me = cc->p2;
138 //struct PeerContext *p1 = cc->p1;
140 GNUNET_assert (message != NULL);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Exchanging HELLO of size %d with peer (%s)!\n",
143 (int) GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *)
144 message), GNUNET_i2s (&me->id));
145 GNUNET_assert (GNUNET_OK ==
146 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
148 GNUNET_TRANSPORT_offer_hello (cc->th_p1, message, NULL, NULL);
153 exchange_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
155 struct ConnectingContext *cc = cb_cls;
156 struct PeerContext *me = cc->p1;
158 //struct PeerContext *p2 = cc->p2;
160 GNUNET_assert (message != NULL);
161 GNUNET_assert (GNUNET_OK ==
162 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Exchanging HELLO of size %d from peer %s!\n",
166 (int) GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *)
167 message), GNUNET_i2s (&me->id));
168 GNUNET_TRANSPORT_offer_hello (cc->th_p2, message, NULL, NULL);
172 try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
174 struct ConnectingContext *cc = cls;
175 struct PeerContext *p1 = cc->p1;
176 struct PeerContext *p2 = cc->p2;
178 cc->tct = GNUNET_SCHEDULER_NO_TASK;
179 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking peers to connect...\n");
183 /* FIXME: 'pX.id' may still be all-zeros here... */
184 GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id);
185 GNUNET_TRANSPORT_try_connect (cc->th_p2, &p1->id);
188 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
193 * Start a peer with the given configuration
194 * @param rec receive callback
195 * @param nc connect callback
196 * @param nd disconnect callback
197 * @param cb_cls closure for callback
198 * @return the peer context
201 GNUNET_TRANSPORT_TESTING_start_peer (const char *cfgname,
202 GNUNET_TRANSPORT_ReceiveCallback rec,
203 GNUNET_TRANSPORT_NotifyConnect nc,
204 GNUNET_TRANSPORT_NotifyDisconnect nd,
207 if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", cfgname);
213 struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
215 p->cfg = GNUNET_CONFIGURATION_create ();
217 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
218 if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
219 GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", "SERVICEHOME",
221 if (NULL != p->servicehome)
222 GNUNET_DISK_directory_remove (p->servicehome);
224 GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
225 "gnunet-service-arm", "-c", cfgname,
241 GNUNET_TRANSPORT_connect (p->cfg, NULL, p, ¬ify_receive,
242 ¬ify_connect, ¬ify_disconnect);
243 GNUNET_assert (p->th != NULL);
248 * shutdown the given peer
252 GNUNET_TRANSPORT_TESTING_stop_peer (struct PeerContext *p)
254 GNUNET_assert (p != NULL);
256 GNUNET_TRANSPORT_disconnect (p->th);
258 if (NULL != p->arm_proc)
260 if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
261 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
262 GNUNET_OS_process_wait (p->arm_proc);
263 GNUNET_OS_process_close (p->arm_proc);
266 if (p->servicehome != NULL)
268 GNUNET_DISK_directory_remove (p->servicehome);
269 GNUNET_free (p->servicehome);
273 GNUNET_CONFIGURATION_destroy (p->cfg);
279 * Connect the two given peers and call the callback when both peers report the
280 * inbound connect. Remarks: start_peer's notify_connect callback can be called
284 * @param cb the callback to call
285 * @param cb_cls callback cls
286 * @return connect context
288 GNUNET_TRANSPORT_TESTING_ConnectRequest
289 GNUNET_TRANSPORT_TESTING_connect_peers (struct PeerContext *p1,
290 struct PeerContext *p2,
291 GNUNET_TRANSPORT_TESTING_connect_cb cb,
294 struct ConnectingContext *cc =
295 GNUNET_malloc (sizeof (struct ConnectingContext));
297 GNUNET_assert (p1 != NULL);
298 GNUNET_assert (p2 != NULL);
307 GNUNET_TRANSPORT_connect (cc->p1->cfg, NULL, cc, NULL,
308 ¬ify_connect_internal, NULL);
311 GNUNET_TRANSPORT_connect (cc->p2->cfg, NULL, cc, NULL,
312 ¬ify_connect_internal, NULL);
314 GNUNET_assert (cc->th_p1 != NULL);
315 GNUNET_assert (cc->th_p2 != NULL);
317 p1->ghh = GNUNET_TRANSPORT_get_hello (cc->th_p1, &exchange_hello, cc);
318 p2->ghh = GNUNET_TRANSPORT_get_hello (cc->th_p2, &exchange_hello_last, cc);
320 cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
325 * Cancel the request to connect two peers
326 * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
327 * @param cc a connect request handle
329 void GNUNET_TRANSPORT_TESTING_connect_peers_cancel
330 (GNUNET_TRANSPORT_TESTING_ConnectRequest ccr)
332 struct ConnectingContext *cc = ccr;
335 GNUNET_TRANSPORT_get_hello_cancel (cc->p1->ghh);
336 GNUNET_TRANSPORT_get_hello_cancel (cc->p2->ghh);
338 if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
339 GNUNET_SCHEDULER_cancel (cc->tct);
341 cc->tct = GNUNET_SCHEDULER_NO_TASK;
343 GNUNET_TRANSPORT_disconnect (cc->th_p1);
344 GNUNET_TRANSPORT_disconnect (cc->th_p2);
351 * Some utility functions
355 * Removes all directory separators from absolute filename
356 * @param file the absolute file name, e.g. as found in argv[0]
357 * @return extracted file name, has to be freed by caller
360 extract_filename (const char *file)
362 char *pch = strdup (file);
364 char *filename = NULL;
367 if (NULL != strstr (pch, "/"))
369 pch = strtok (pch, "/");
372 pch = strtok (NULL, "/");
382 res = strdup (filename);
383 GNUNET_free (backup);
388 * Extracts the test filename from an absolute file name and removes the extension
389 * @param file absolute file name
390 * @param dest where to store result
393 GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest)
395 char *filename = extract_filename (file);
396 char *backup = filename;
399 if (filename == NULL)
403 filename = strstr (filename, "tes");
404 if (filename == NULL)
408 if (NULL != (dotexe = strstr (filename, ".exe")))
411 if (filename == NULL)
420 /* create filename */
421 GNUNET_asprintf (dest, "%s", filename);
422 GNUNET_free (backup);
427 * Extracts the filename from an absolute file name and removes the extension
428 * @param file absolute file name
429 * @param dest where to store result
432 GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest)
434 char *src = extract_filename (file);
437 split = strstr (src, ".");
442 GNUNET_asprintf (dest, "%s", src);
448 * Extracts the plugin anme from an absolute file name and the test name
449 * @param file absolute file name
450 * @param test test name
451 * @param dest where to store result
454 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
455 const char *test, char **dest)
457 char *e = extract_filename (file);
458 char *t = extract_filename (test);
460 char *filename = NULL;
467 filename = strstr (e, "tes");
468 if (filename == NULL)
472 if (NULL != (dotexe = strstr (filename, ".exe")))
476 filename = strstr (filename, t);
477 if (filename == NULL)
481 filename += strlen (t);
483 GNUNET_asprintf (dest, "%s", filename);
495 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
496 * if existing ".exe"-prefix and adds the peer-number
497 * @param file filename of the test, e.g. argv[0]
498 * @param cfgname where to write the result
499 * @param count peer number
502 GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
505 char *filename = extract_filename (file);
506 char *backup = filename;
509 if (filename == NULL)
513 filename = strstr (filename, "tes");
514 if (filename == NULL)
518 if (NULL != (dotexe = strstr (filename, ".exe")))
521 if (filename == NULL)
530 /* create cfg filename */
531 GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count);
532 GNUNET_free (backup);
537 /* end of transport_testing.h */