8875afb8ec3ab8a51c8eef38c78a3c4c9177713b
[oweals/gnunet.git] / src / transport / transport-testing.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 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 2, 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 transport-testing.c
23  * @brief testing lib for transport service
24  *
25  * @author Matthias Wachs
26  */
27
28 #include "transport-testing.h"
29
30
31 static struct PeerContext *
32 find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
33                    const struct GNUNET_PeerIdentity *peer)
34 {
35   GNUNET_assert (tth != NULL);
36   struct PeerContext *t = tth->p_head;
37
38   while (t != NULL)
39   {
40     if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity)))
41       break;
42     t = t->next;
43   }
44
45   return t;
46 }
47
48
49 static struct ConnectingContext *
50 find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
51                          struct PeerContext *p1, struct PeerContext *p2)
52 {
53   GNUNET_assert (tth != NULL);
54   struct ConnectingContext *cc = tth->cc_head;
55
56   while (cc != NULL)
57   {
58     if ((cc->p1 == p1) && (cc->p2 == p2))
59       break;
60     if ((cc->p1 == p2) && (cc->p2 == p1))
61       break;
62     cc = cc->next;
63   }
64
65   return cc;
66 }
67
68
69 static void
70 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
71 {
72   struct PeerContext *p = cls;
73   char *p2_s;
74   struct PeerContext *p2;
75
76   GNUNET_assert (NULL != p);
77   GNUNET_assert (NULL != p->tth);
78   p2 = find_peer_context (p->tth, peer);
79   if (p->nc != NULL)
80     p->nc (p->cb_cls, peer);
81
82   if (p2 != NULL)
83     GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
84   else
85     GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
86   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
87                    "Peers %s connected to peer %u (`%s')\n", p2_s, p->no,
88                    GNUNET_i2s (&p->id));
89   GNUNET_free (p2_s);
90
91   /* Find ConnectingContext */
92   struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2);
93
94   if (cc == NULL)
95     return;
96
97   if (p == cc->p1)
98     cc->p1_c = GNUNET_YES;
99
100   if (p == cc->p2)
101     cc->p2_c = GNUNET_YES;
102
103   if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
104   {
105     cc->cb (cc->p1, cc->p2, cc->cb_cls);
106     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc);
107   }
108 }
109
110
111 static void
112 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
113 {
114   struct PeerContext *p = cls;
115
116   /* Find PeerContext */
117   int no = 0;
118   struct PeerContext *p2 = NULL;
119
120   if (p != NULL)
121   {
122     GNUNET_assert (p->tth != NULL);
123     p2 = find_peer_context (p->tth, peer);
124     no = p->no;
125   }
126
127   char *p2_s;
128
129   if (p2 != NULL)
130     GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
131   else
132     GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
133   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
134                    "Peers %s disconnected from peer %u (`%s')\n", p2_s, no,
135                    GNUNET_i2s (&p->id));
136   GNUNET_free (p2_s);
137
138   if (p == NULL)
139     return;
140   if (p->nd != NULL)
141     p->nd (p->cb_cls, peer);
142 }
143
144
145 static void
146 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
147                 const struct GNUNET_MessageHeader *message)
148 {
149   struct PeerContext *p = cls;
150
151   if (p == NULL)
152     return;
153   if (p->rec != NULL)
154     p->rec (p->cb_cls, peer, message);
155 }
156
157
158 static void
159 get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
160 {
161   struct PeerContext *p = cb_cls;
162   struct GNUNET_PeerIdentity hello_id;
163
164   GNUNET_assert (message != NULL);
165   GNUNET_assert (GNUNET_OK ==
166                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
167                                       message, &hello_id));
168   GNUNET_assert (0 == memcmp (&hello_id, &p->id, sizeof (hello_id)));
169   GNUNET_free_non_null (p->hello);
170   p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
171
172   if (NULL != p->start_cb)
173   {
174     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
175                      "Peer %u (`%s') successfully started\n", p->no,
176                      GNUNET_i2s (&p->id));
177     p->start_cb (p, p->cb_cls);
178     p->start_cb = NULL;
179   }
180 }
181
182
183 static void
184 try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
185 {
186   struct ConnectingContext *cc = cls;
187   struct PeerContext *p1 = cc->p1;
188   struct PeerContext *p2 = cc->p2;
189
190   cc->tct = GNUNET_SCHEDULER_NO_TASK;
191   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
192     return;
193
194   GNUNET_assert (cc != NULL);
195   GNUNET_assert (cc->p1 != NULL);
196   GNUNET_assert (cc->p2 != NULL);
197
198   char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
199
200   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
201                    "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
202                    p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s,
203                    GNUNET_HELLO_size (cc->p2->hello));
204   GNUNET_free (p2_s);
205
206   GNUNET_TRANSPORT_offer_hello (cc->th_p1,
207                                 (const struct GNUNET_MessageHeader *) cc->
208                                 p2->hello, NULL, NULL);
209   GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id, NULL, NULL); /*FIXME TRY_CONNECT change */
210
211   cc->tct =
212       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
213 }
214
215
216 /**
217  * Start a peer with the given configuration
218  * @param tth the testing handle
219  * @param cfgname configuration file
220  * @param peer_id a unique number to identify the peer
221  * @param rec receive callback
222  * @param nc connect callback
223  * @param nd disconnect callback
224  * @param start_cb start callback
225  * @param cb_cls closure for callback
226  * @return the peer context
227  */
228 struct PeerContext *
229 GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
230                                      const char *cfgname, int peer_id,
231                                      GNUNET_TRANSPORT_ReceiveCallback rec,
232                                      GNUNET_TRANSPORT_NotifyConnect nc,
233                                      GNUNET_TRANSPORT_NotifyDisconnect nd,
234                                      GNUNET_TRANSPORT_TESTING_start_cb start_cb,
235                                      void *cb_cls)
236 {
237   char *emsg = NULL;
238   struct GNUNET_PeerIdentity *dummy;
239
240   GNUNET_assert (NULL != tth);
241   GNUNET_assert (NULL != tth->tl_system);
242
243   if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
244   {
245     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
246                      "File not found: `%s' \n", cfgname);
247     return NULL;
248   }
249
250   struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
251   GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p);
252
253   /* Create configuration and call testing lib to modify it */
254   p->cfg = GNUNET_CONFIGURATION_create ();
255   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
256
257   if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg))
258   {
259     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
260                      "Testing library failed to create unique configuration based on `%s'\n",
261                      cfgname);
262     GNUNET_free (p);
263     return NULL;
264   }
265
266   p->no = peer_id;
267   /* Configure peer with configuration */
268   p->peer = GNUNET_TESTING_peer_configure (tth->tl_system, p->cfg, p->no, NULL, &emsg);
269   if (NULL == p->peer)
270   {
271     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
272                      "Testing library failed to create unique configuration based on `%s': `%s'\n",
273                      cfgname, emsg);
274     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
275     GNUNET_free_non_null (emsg);
276     return NULL;
277   }
278   GNUNET_free_non_null (emsg);
279   if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
280   {
281     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
282                      "Testing library failed to create unique configuration based on `%s'\n",
283                      cfgname);
284     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
285     return NULL;
286   }
287
288   memset(&dummy, '\0', sizeof (dummy));
289   GNUNET_TESTING_peer_get_identity (p->peer, &p->id);
290   if (0 == memcmp (&dummy, &p->id, sizeof (struct GNUNET_PeerIdentity)))
291   {
292     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
293                      "Testing library failed to obtain peer identity for peer %u\n",
294                      p->no);
295     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
296     return NULL;
297   }
298   else
299   {
300     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
301                      "Peer %u configured with identity `%s'\n",
302                      p->no,
303                      GNUNET_i2s (&p->id));
304   }
305
306   p->tth = tth;
307   p->nc = nc;
308   p->nd = nd;
309   p->rec = rec;
310   p->start_cb = start_cb;
311   if (cb_cls != NULL)
312     p->cb_cls = cb_cls;
313   else
314     p->cb_cls = p;
315
316   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
317                                     &notify_receive,
318                                     &notify_connect, &notify_disconnect);
319   if (NULL == p->th)
320   {
321     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
322                      "Failed to connect to transport service for peer  `%s': `%s'\n",
323                      cfgname, emsg);
324     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
325     return NULL;
326   }
327
328   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
329   GNUNET_assert (p->ghh != NULL);
330
331   return p;
332 }
333
334 /**
335 * Restart the given peer
336 * @param tth testing handle
337 * @param p the peer
338 * @param cfgname the cfg file used to restart
339 * @param restart_cb callback to call when restarted
340 * @param cb_cls callback closure
341 * @return GNUNET_OK in success otherwise GNUNET_SYSERR
342 */
343 int
344 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
345                                        *tth, struct PeerContext *p,
346                                        const char *cfgname,
347                                        GNUNET_TRANSPORT_TESTING_start_cb
348                                        restart_cb, void *cb_cls)
349 {
350   GNUNET_assert (tth != NULL);
351   GNUNET_assert (p != NULL);
352   GNUNET_assert (NULL != p->peer);
353
354   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
355                    "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
356
357   /* shutdown */
358   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
359                    "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
360   if (NULL != p->ghh)
361     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
362   p->ghh = NULL;
363
364   if (NULL != p->th)
365     GNUNET_TRANSPORT_disconnect (p->th);
366
367   if (GNUNET_SYSERR == GNUNET_TESTING_peer_stop(p->peer))
368   {
369     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
370                      "Failed to stop peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
371     return GNUNET_SYSERR;
372   }
373
374   sleep (5);
375
376   /* restart */
377   if (GNUNET_SYSERR == GNUNET_TESTING_peer_start(p->peer))
378   {
379     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
380                      "Failed to restart peer %u (`%s')\n",
381                      p->no, GNUNET_i2s (&p->id));
382     return GNUNET_SYSERR;
383   }
384
385   GNUNET_assert (p->th != NULL);
386   GNUNET_assert (p->start_cb == NULL);
387   p->start_cb = restart_cb;
388   p->cb_cls = cb_cls;
389
390   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
391                                     &notify_receive,
392                                     &notify_connect,
393                                     &notify_disconnect);
394   GNUNET_assert (NULL != p->th);
395
396   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
397   GNUNET_assert (p->ghh != NULL);
398   return GNUNET_OK;
399 }
400
401
402 /**
403  * shutdown the given peer
404  * @param tth testing handle
405  * @param p the peer
406  */
407 void
408 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
409                                     struct PeerContext *p)
410 {
411   GNUNET_assert (p != NULL);
412   if (p->ghh != NULL)
413   {
414     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
415     p->ghh = NULL;
416   }
417   if (p->th != NULL)
418   {
419     GNUNET_TRANSPORT_disconnect (p->th);
420     p->th = NULL;
421   }
422
423   if (p->peer != NULL)
424   {
425     if (GNUNET_OK != GNUNET_TESTING_peer_stop (p->peer))
426     {
427       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
428                        "Testing lib failed to stop peer %u (`%s') \n", p->no,
429                        GNUNET_i2s (&p->id));
430     }
431     GNUNET_TESTING_peer_destroy (p->peer);
432     p->peer = NULL;
433   }
434
435   if (p->hello != NULL)
436   {
437     GNUNET_free (p->hello);
438     p->hello = NULL;
439   }
440   if (p->cfg != NULL)
441   {
442     GNUNET_CONFIGURATION_destroy (p->cfg);
443     p->cfg = NULL;
444   }
445   GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p);
446   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
447                    "Peer %u (`%s') stopped \n", p->no,
448                    GNUNET_i2s (&p->id));
449   GNUNET_free (p);
450 }
451
452
453 /**
454  * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
455  *
456  * Remarks: start_peer's notify_connect callback can be called before.
457  *
458  * @param tth transport testing handle
459  * @param p1 peer 1
460  * @param p2 peer 2
461  * @param cb the callback to call when both peers notified that they are connected
462  * @param cls callback cls
463  * @return a connect request handle
464  */
465 GNUNET_TRANSPORT_TESTING_ConnectRequest
466 GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
467                                         struct PeerContext *p1,
468                                         struct PeerContext *p2,
469                                         GNUNET_TRANSPORT_TESTING_connect_cb cb,
470                                         void *cls)
471 {
472   GNUNET_assert (tth != NULL);
473
474   struct ConnectingContext *cc =
475       GNUNET_malloc (sizeof (struct ConnectingContext));
476
477   GNUNET_assert (p1 != NULL);
478   GNUNET_assert (p2 != NULL);
479   cc->p1 = p1;
480   cc->p2 = p2;
481   cc->cb = cb;
482   if (cls != NULL)
483     cc->cb_cls = cls;
484   else
485     cc->cb_cls = cc;
486   cc->th_p1 = p1->th;
487   cc->th_p2 = p2->th;
488   GNUNET_assert (cc->th_p1 != NULL);
489   GNUNET_assert (cc->th_p2 != NULL);
490   GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc);
491   cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
492   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
493                    "New connect request %p\n", cc);
494
495   return cc;
496 }
497
498
499 /**
500  * Cancel the request to connect two peers
501  * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
502  *
503  * @param tth transport testing handle
504  * @param ccr a connect request handle
505  */
506 void
507 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
508                                                GNUNET_TRANSPORT_TESTING_handle
509                                                *tth,
510                                                GNUNET_TRANSPORT_TESTING_ConnectRequest
511                                                ccr)
512 {
513   struct ConnectingContext *cc = ccr;
514
515   GNUNET_assert (tth != NULL);
516
517   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
518                    "Canceling connect request %p!\n", cc);
519
520   if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
521     GNUNET_SCHEDULER_cancel (cc->tct);
522   cc->tct = GNUNET_SCHEDULER_NO_TASK;
523
524   GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc);
525   GNUNET_free (cc);
526 }
527
528
529 /**
530  * Clean up the transport testing
531  * @param tth transport testing handle
532  */
533 void
534 GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth)
535 {
536   struct ConnectingContext *cc = tth->cc_head;
537   struct ConnectingContext *ct = NULL;
538   struct PeerContext *p = tth->p_head;
539   struct PeerContext *t = NULL;
540
541   GNUNET_assert (tth != NULL);
542
543   while (cc != tth->cc_tail)
544   {
545     ct = cc->next;
546     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
547                      "Developer forgot to cancel connect request %p!\n", cc);
548     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
549     cc = ct;
550   }
551
552   while (p != NULL)
553   {
554     t = p->next;
555     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
556                      "Developer forgot to stop peer!\n");
557     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
558     p = t;
559   }
560
561   GNUNET_TESTING_system_destroy (tth->tl_system, GNUNET_YES);
562
563   GNUNET_free (tth);
564   tth = NULL;
565 }
566
567
568 /**
569  * Initialize the transport testing
570  * @return transport testing handle
571  */
572 struct GNUNET_TRANSPORT_TESTING_handle *
573 GNUNET_TRANSPORT_TESTING_init ()
574 {
575   struct GNUNET_TRANSPORT_TESTING_handle *tth;
576
577   /* prepare hostkeys */
578   tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle));
579
580   /* Init testing the testing lib */
581   tth->tl_system = GNUNET_TESTING_system_create ("transport-testing", NULL, NULL);
582   if (NULL == tth->tl_system)
583   {
584     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize testing library!\n"));
585     GNUNET_free (tth);
586     return NULL;
587   }
588
589   return tth;
590 }
591
592
593 /*
594  * Some utility functions
595  */
596
597 /**
598  * Removes all directory separators from absolute filename
599  * @param file the absolute file name, e.g. as found in argv[0]
600  * @return extracted file name, has to be freed by caller
601  */
602 static char *
603 extract_filename (const char *file)
604 {
605   char *pch = GNUNET_strdup (file);
606   char *backup = pch;
607   char *filename = NULL;
608   char *res;
609 #if WINDOWS
610   if ((strlen (pch) >= 3) && pch[1] == ':')
611   {
612     if (NULL != strstr (pch, "\\"))
613     {
614       pch = strtok (pch, "\\");
615       while (pch != NULL)
616       {
617         pch = strtok (NULL, "\\");
618         if (pch != NULL)
619           filename = pch;
620       }
621     }
622   }
623   if (filename != NULL)
624     pch = filename; /* If we miss the next condition, filename = pch will
625                      * not harm us.
626                      */
627 #endif
628   if (NULL != strstr (pch, "/"))
629   {
630     pch = strtok (pch, "/");
631     while (pch != NULL)
632     {
633       pch = strtok (NULL, "/");
634       if (pch != NULL)
635       {
636         filename = pch;
637       }
638     }
639   }
640   else
641     filename = pch;
642
643   res = GNUNET_strdup (filename);
644   GNUNET_free (backup);
645   return res;
646 }
647
648
649 /**
650  * Extracts the test filename from an absolute file name and removes the extension
651  * @param file absolute file name
652  * @param dest where to store result
653  */
654 void
655 GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest)
656 {
657   char *filename = extract_filename (file);
658   char *backup = filename;
659   char *dotexe;
660
661   if (filename == NULL)
662     goto fail;
663
664   /* remove "lt-" */
665   filename = strstr (filename, "tes");
666   if (filename == NULL)
667     goto fail;
668
669   /* remove ".exe" */
670   if (NULL != (dotexe = strstr (filename, ".exe")))
671     dotexe[0] = '\0';
672
673   goto suc;
674
675 fail:
676   (*dest) = NULL;
677   return;
678
679 suc:
680   /* create filename */
681   GNUNET_asprintf (dest, "%s", filename);
682   GNUNET_free (backup);
683 }
684
685
686 /**
687  * Extracts the filename from an absolute file name and removes the extension
688  * @param file absolute file name
689  * @param dest where to store result
690  */
691 void
692 GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest)
693 {
694   char *src = extract_filename (file);
695   char *split;
696
697   split = strstr (src, ".");
698   if (split != NULL)
699   {
700     split[0] = '\0';
701   }
702   GNUNET_asprintf (dest, "%s", src);
703   GNUNET_free (src);
704 }
705
706
707 /**
708  * Extracts the plugin name from an absolute file name and the test name
709  *
710  * @param file absolute file name
711  * @param test test name
712  * @param dest where to store result
713  */
714 void
715 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
716                                                const char *test, char **dest)
717 {
718   char *filename;
719   char *dotexe;
720   char *e = extract_filename (file);
721   char *t = extract_filename (test);
722
723   if (NULL == e)
724     goto fail;
725   /* remove "lt-" */
726   filename = strstr (e, "tes");
727   if (NULL == filename)
728     goto fail;
729   /* remove ".exe" */
730   if (NULL != (dotexe = strstr (filename, ".exe")))
731     dotexe[0] = '\0';
732
733   /* find last _ */
734   filename = strstr (filename, t);
735   if (NULL == filename)
736     goto fail;
737   /* copy plugin */
738   filename += strlen (t);
739   if ('\0' != *filename)
740     filename++;
741   GNUNET_asprintf (dest, "%s", filename);
742   goto suc;
743 fail:
744   (*dest) = NULL;
745 suc:
746   GNUNET_free (t);
747   GNUNET_free (e);
748 }
749
750
751 /**
752  * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
753  * if existing ".exe"-prefix and adds the peer-number
754  *
755  * @param file filename of the test, e.g. argv[0]
756  * @param dest where to write the filename
757  * @param count peer number
758  */
759 void
760 GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
761                                           int count)
762 {
763   char *filename = extract_filename (file);
764   char *backup = filename;
765   char *dotexe;
766
767   if (NULL == filename)
768     goto fail;
769   /* remove "lt-" */
770   filename = strstr (filename, "tes");
771   if (NULL == filename)
772     goto fail;
773   /* remove ".exe" */
774   if (NULL != (dotexe = strstr (filename, ".exe")))
775     dotexe[0] = '\0';
776   GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count);
777   GNUNET_free (backup);
778   return;
779 fail:
780   (*dest) = NULL;
781   GNUNET_free (backup);
782 }
783
784
785 /* end of transport-testing.c */