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