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