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