-doxygen
[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 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 transport-testing.c
23  * @brief testing lib for transport service
24  *
25  * @author Matthias Wachs
26  */
27 #include "transport-testing.h"
28
29
30 static struct PeerContext *
31 find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
32                    const struct GNUNET_PeerIdentity *peer)
33 {
34   GNUNET_assert (tth != NULL);
35   struct PeerContext *t = tth->p_head;
36
37   while (t != NULL)
38   {
39     if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity)))
40       break;
41     t = t->next;
42   }
43
44   return t;
45 }
46
47
48 static struct ConnectingContext *
49 find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
50                          struct PeerContext *p1, struct PeerContext *p2)
51 {
52   GNUNET_assert (tth != NULL);
53   struct ConnectingContext *cc = tth->cc_head;
54
55   while (cc != NULL)
56   {
57     if ((cc->p1 == p1) && (cc->p2 == p2))
58       break;
59     if ((cc->p1 == p2) && (cc->p2 == p1))
60       break;
61     cc = cc->next;
62   }
63
64   return cc;
65 }
66
67
68 static void
69 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
70 {
71   struct PeerContext *p = cls;
72   char *p2_s;
73   struct PeerContext *p2;
74
75   GNUNET_assert (NULL != p);
76   GNUNET_assert (NULL != p->tth);
77   p2 = find_peer_context (p->tth, peer);
78   if (p->nc != NULL)
79     p->nc (p->cb_cls, peer);
80
81   if (p2 != NULL)
82     GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
83   else
84     GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
85   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
86                    "Peers %s connected to peer %u (`%s')\n", p2_s, p->no,
87                    GNUNET_i2s (&p->id));
88   GNUNET_free (p2_s);
89
90   /* Find ConnectingContext */
91   struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2);
92
93   if (cc == NULL)
94     return;
95
96   if (p == cc->p1)
97     cc->p1_c = GNUNET_YES;
98
99   if (p == cc->p2)
100     cc->p2_c = GNUNET_YES;
101
102   if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
103   {
104     cc->cb (cc->p1, cc->p2, cc->cb_cls);
105     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc);
106   }
107 }
108
109
110 static void
111 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
112 {
113   struct PeerContext *p = cls;
114
115   /* Find PeerContext */
116   int no = 0;
117   struct PeerContext *p2 = NULL;
118
119   if (p != NULL)
120   {
121     GNUNET_assert (p->tth != NULL);
122     p2 = find_peer_context (p->tth, peer);
123     no = p->no;
124   }
125
126   char *p2_s;
127
128   if (p2 != NULL)
129     GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
130   else
131     GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
132   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
133                    "Peers %s disconnected from peer %u (`%s')\n", p2_s, no,
134                    GNUNET_i2s (&p->id));
135   GNUNET_free (p2_s);
136
137   if (p == NULL)
138     return;
139   if (p->nd != NULL)
140     p->nd (p->cb_cls, peer);
141 }
142
143
144 static void
145 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
146                 const struct GNUNET_MessageHeader *message)
147 {
148   struct PeerContext *p = cls;
149
150   if (p == NULL)
151     return;
152   if (p->rec != NULL)
153     p->rec (p->cb_cls, peer, message);
154 }
155
156
157 static void
158 get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
159 {
160   struct PeerContext *p = cb_cls;
161   struct GNUNET_PeerIdentity hello_id;
162
163   GNUNET_assert (message != NULL);
164   GNUNET_assert (GNUNET_OK ==
165                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
166                                       message, &hello_id));
167   GNUNET_assert (0 == memcmp (&hello_id, &p->id, sizeof (hello_id)));
168   GNUNET_free_non_null (p->hello);
169   p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
170
171   if (NULL != p->start_cb)
172   {
173     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
174                      "Peer %u (`%s') successfully started\n", p->no,
175                      GNUNET_i2s (&p->id));
176     p->start_cb (p, p->cb_cls);
177     p->start_cb = NULL;
178   }
179 }
180
181
182 static void
183 try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
184 {
185   struct ConnectingContext *cc = cls;
186   struct PeerContext *p1 = cc->p1;
187   struct PeerContext *p2 = cc->p2;
188
189   cc->tct = GNUNET_SCHEDULER_NO_TASK;
190   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
191     return;
192
193   GNUNET_assert (cc != NULL);
194   GNUNET_assert (cc->p1 != NULL);
195   GNUNET_assert (cc->p2 != NULL);
196
197   char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
198
199   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
200                    "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
201                    p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s,
202                    GNUNET_HELLO_size (cc->p2->hello));
203   GNUNET_free (p2_s);
204
205   GNUNET_TRANSPORT_offer_hello (cc->th_p1,
206                                 (const struct GNUNET_MessageHeader *) cc->
207                                 p2->hello, NULL, NULL);
208   GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id, NULL, NULL); /*FIXME TRY_CONNECT change */
209
210   cc->tct =
211       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
212 }
213
214
215 /**
216  * Start a peer with the given configuration
217  * @param tth the testing handle
218  * @param cfgname configuration file
219  * @param peer_id a unique number to identify the peer
220  * @param rec receive callback
221  * @param nc connect callback
222  * @param nd disconnect callback
223  * @param start_cb start callback
224  * @param cb_cls closure for callback
225  * @return the peer context
226  */
227 struct PeerContext *
228 GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
229                                      const char *cfgname, int peer_id,
230                                      GNUNET_TRANSPORT_ReceiveCallback rec,
231                                      GNUNET_TRANSPORT_NotifyConnect nc,
232                                      GNUNET_TRANSPORT_NotifyDisconnect nd,
233                                      GNUNET_TRANSPORT_TESTING_start_cb start_cb,
234                                      void *cb_cls)
235 {
236   char *emsg = NULL;
237   struct GNUNET_PeerIdentity *dummy;
238
239   GNUNET_assert (NULL != tth);
240   GNUNET_assert (NULL != tth->tl_system);
241
242   if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
243   {
244     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
245                      "File not found: `%s' \n", cfgname);
246     return NULL;
247   }
248
249   struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
250   GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p);
251
252   /* Create configuration and call testing lib to modify it */
253   p->cfg = GNUNET_CONFIGURATION_create ();
254   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
255
256   if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg))
257   {
258     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
259                      "Testing library failed to create unique configuration based on `%s'\n",
260                      cfgname);
261     GNUNET_free (p);
262     return NULL;
263   }
264
265   p->no = peer_id;
266   /* Configure peer with configuration */
267   p->peer = GNUNET_TESTING_peer_configure (tth->tl_system, p->cfg, p->no, NULL, &emsg);
268   if (NULL == p->peer)
269   {
270     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
271                      "Testing library failed to create unique configuration based on `%s': `%s'\n",
272                      cfgname, emsg);
273     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
274     GNUNET_free_non_null (emsg);
275     return NULL;
276   }
277   GNUNET_free_non_null (emsg);
278   if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
279   {
280     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
281                      "Testing library failed to create unique configuration based on `%s'\n",
282                      cfgname);
283     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
284     return NULL;
285   }
286
287   memset(&dummy, '\0', sizeof (dummy));
288   GNUNET_TESTING_peer_get_identity (p->peer, &p->id);
289   if (0 == memcmp (&dummy, &p->id, sizeof (struct GNUNET_PeerIdentity)))
290   {
291     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
292                      "Testing library failed to obtain peer identity for peer %u\n",
293                      p->no);
294     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
295     return NULL;
296   }
297   else
298   {
299     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
300                      "Peer %u configured with identity `%s'\n",
301                      p->no,
302                      GNUNET_i2s_full (&p->id));
303   }
304
305   p->tth = tth;
306   p->nc = nc;
307   p->nd = nd;
308   p->rec = rec;
309   p->start_cb = start_cb;
310   if (cb_cls != NULL)
311     p->cb_cls = cb_cls;
312   else
313     p->cb_cls = p;
314
315   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
316                                     &notify_receive,
317                                     &notify_connect, &notify_disconnect);
318   if (NULL == p->th)
319   {
320     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
321                      "Failed to connect to transport service for peer  `%s': `%s'\n",
322                      cfgname, emsg);
323     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
324     return NULL;
325   }
326
327   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
328   GNUNET_assert (p->ghh != NULL);
329
330   return p;
331 }
332
333 /**
334 * Restart the given peer
335 * @param tth testing handle
336 * @param p the peer
337 * @param cfgname the cfg file used to restart
338 * @param restart_cb callback to call when restarted
339 * @param cb_cls callback closure
340 * @return GNUNET_OK in success otherwise GNUNET_SYSERR
341 */
342 int
343 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
344                                        *tth, struct PeerContext *p,
345                                        const char *cfgname,
346                                        GNUNET_TRANSPORT_TESTING_start_cb
347                                        restart_cb, void *cb_cls)
348 {
349   GNUNET_assert (tth != NULL);
350   GNUNET_assert (p != NULL);
351   GNUNET_assert (NULL != p->peer);
352
353   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
354                    "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
355
356   /* shutdown */
357   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
358                    "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
359   if (NULL != p->ghh)
360     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
361   p->ghh = NULL;
362
363   if (NULL != p->th)
364     GNUNET_TRANSPORT_disconnect (p->th);
365
366   if (GNUNET_SYSERR == GNUNET_TESTING_peer_stop(p->peer))
367   {
368     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
369                      "Failed to stop peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
370     return GNUNET_SYSERR;
371   }
372
373   sleep (5);
374
375   /* restart */
376   if (GNUNET_SYSERR == GNUNET_TESTING_peer_start(p->peer))
377   {
378     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
379                      "Failed to restart peer %u (`%s')\n",
380                      p->no, GNUNET_i2s (&p->id));
381     return GNUNET_SYSERR;
382   }
383
384   GNUNET_assert (p->th != NULL);
385   GNUNET_assert (p->start_cb == NULL);
386   p->start_cb = restart_cb;
387   p->cb_cls = cb_cls;
388
389   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
390                                     &notify_receive,
391                                     &notify_connect,
392                                     &notify_disconnect);
393   GNUNET_assert (NULL != p->th);
394
395   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
396   GNUNET_assert (p->ghh != NULL);
397   return GNUNET_OK;
398 }
399
400
401 /**
402  * shutdown the given peer
403  * @param tth testing handle
404  * @param p the peer
405  */
406 void
407 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
408                                     struct PeerContext *p)
409 {
410   GNUNET_assert (p != NULL);
411   if (p->ghh != NULL)
412   {
413     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
414     p->ghh = NULL;
415   }
416   if (p->th != NULL)
417   {
418     GNUNET_TRANSPORT_disconnect (p->th);
419     p->th = NULL;
420   }
421
422   if (p->peer != NULL)
423   {
424     if (GNUNET_OK != GNUNET_TESTING_peer_stop (p->peer))
425     {
426       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
427                        "Testing lib failed to stop peer %u (`%s') \n", p->no,
428                        GNUNET_i2s (&p->id));
429     }
430     GNUNET_TESTING_peer_destroy (p->peer);
431     p->peer = NULL;
432   }
433
434   if (p->hello != NULL)
435   {
436     GNUNET_free (p->hello);
437     p->hello = NULL;
438   }
439   if (p->cfg != NULL)
440   {
441     GNUNET_CONFIGURATION_destroy (p->cfg);
442     p->cfg = NULL;
443   }
444   GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p);
445   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
446                    "Peer %u (`%s') stopped \n", p->no,
447                    GNUNET_i2s (&p->id));
448   GNUNET_free (p);
449 }
450
451
452 /**
453  * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
454  *
455  * Remarks: start_peer's notify_connect callback can be called before.
456  *
457  * @param tth transport testing handle
458  * @param p1 peer 1
459  * @param p2 peer 2
460  * @param cb the callback to call when both peers notified that they are connected
461  * @param cls callback cls
462  * @return a connect request handle
463  */
464 GNUNET_TRANSPORT_TESTING_ConnectRequest
465 GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
466                                         struct PeerContext *p1,
467                                         struct PeerContext *p2,
468                                         GNUNET_TRANSPORT_TESTING_connect_cb cb,
469                                         void *cls)
470 {
471   GNUNET_assert (tth != NULL);
472
473   struct ConnectingContext *cc =
474       GNUNET_malloc (sizeof (struct ConnectingContext));
475
476   GNUNET_assert (p1 != NULL);
477   GNUNET_assert (p2 != NULL);
478   cc->p1 = p1;
479   cc->p2 = p2;
480   cc->cb = cb;
481   if (cls != NULL)
482     cc->cb_cls = cls;
483   else
484     cc->cb_cls = cc;
485   cc->th_p1 = p1->th;
486   cc->th_p2 = p2->th;
487   GNUNET_assert (cc->th_p1 != NULL);
488   GNUNET_assert (cc->th_p2 != NULL);
489   GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc);
490   cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
491   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
492                    "New connect request %p\n", cc);
493
494   return cc;
495 }
496
497
498 /**
499  * Cancel the request to connect two peers
500  * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
501  *
502  * @param tth transport testing handle
503  * @param ccr a connect request handle
504  */
505 void
506 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
507                                                GNUNET_TRANSPORT_TESTING_handle
508                                                *tth,
509                                                GNUNET_TRANSPORT_TESTING_ConnectRequest
510                                                ccr)
511 {
512   struct ConnectingContext *cc = ccr;
513
514   GNUNET_assert (tth != NULL);
515
516   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
517                    "Canceling connect request %p!\n", cc);
518
519   if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
520     GNUNET_SCHEDULER_cancel (cc->tct);
521   cc->tct = GNUNET_SCHEDULER_NO_TASK;
522
523   GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc);
524   GNUNET_free (cc);
525 }
526
527
528 /**
529  * Clean up the transport testing
530  * @param tth transport testing handle
531  */
532 void
533 GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth)
534 {
535   struct ConnectingContext *cc = tth->cc_head;
536   struct ConnectingContext *ct = NULL;
537   struct PeerContext *p = tth->p_head;
538   struct PeerContext *t = NULL;
539
540   GNUNET_assert (tth != NULL);
541
542   while (cc != tth->cc_tail)
543   {
544     ct = cc->next;
545     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
546                      "Developer forgot to cancel connect request %p!\n", cc);
547     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
548     cc = ct;
549   }
550
551   while (p != NULL)
552   {
553     t = p->next;
554     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
555                      "Developer forgot to stop peer!\n");
556     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
557     p = t;
558   }
559
560   GNUNET_TESTING_system_destroy (tth->tl_system, GNUNET_YES);
561
562   GNUNET_free (tth);
563   tth = NULL;
564 }
565
566
567 /**
568  * Initialize the transport testing
569  * @return transport testing handle
570  */
571 struct GNUNET_TRANSPORT_TESTING_handle *
572 GNUNET_TRANSPORT_TESTING_init ()
573 {
574   struct GNUNET_TRANSPORT_TESTING_handle *tth;
575
576   /* prepare hostkeys */
577   tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle));
578
579   /* Init testing the testing lib */
580   tth->tl_system = GNUNET_TESTING_system_create ("transport-testing", NULL,
581                                                  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 */