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