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