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