hunting bugs
[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     return NULL;
282   }
283
284   if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
285   {
286     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
287                      "Testing library failed to create unique configuration based on `%s'\n",
288                      cfgname);
289     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
290     return NULL;
291   }
292
293   memset(&dummy, '\0', sizeof (dummy));
294   GNUNET_TESTING_peer_get_identity (p->peer, &p->id);
295   if (0 == memcmp (&dummy, &p->id, sizeof (dummy)))
296   {
297     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
298                      "Testing library failed to obtain peer identity for peer %u\n",
299                      p->no);
300     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
301     return NULL;
302   }
303   else
304   {
305     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
306                      "Peer %u configured with identity `%s'\n",
307                      p->no,
308                      GNUNET_i2s (&p->id));
309   }
310
311   p->tth = tth;
312   p->nc = nc;
313   p->nd = nd;
314   p->rec = rec;
315   p->start_cb = start_cb;
316   if (cb_cls != NULL)
317     p->cb_cls = cb_cls;
318   else
319     p->cb_cls = p;
320
321   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
322                                     &notify_receive,
323                                     &notify_connect, &notify_disconnect);
324   if (NULL == p->th)
325   {
326     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
327                      "Failed to connect to transport service for peer  `%s': `%s'\n",
328                      cfgname, emsg);
329     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
330     return NULL;
331   }
332
333   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
334   GNUNET_assert (p->ghh != NULL);
335
336   return p;
337 }
338
339 /**
340 * Restart the given peer
341 * @param tth testing handle
342 * @param p the peer
343 * @param cfgname the cfg file used to restart
344 * @param restart_cb callback to call when restarted
345 * @param cb_cls callback closure
346 * @return GNUNET_OK in success otherwise GNUNET_SYSERR
347 */
348 int
349 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
350                                        *tth, struct PeerContext *p,
351                                        const char *cfgname,
352                                        GNUNET_TRANSPORT_TESTING_start_cb
353                                        restart_cb, void *cb_cls)
354 {
355   GNUNET_assert (tth != NULL);
356   GNUNET_assert (p != NULL);
357   GNUNET_assert (NULL != p->peer);
358
359   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
360                    "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
361
362   /* shutdown */
363   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
364                    "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
365   if (NULL != p->ghh)
366     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
367   p->ghh = NULL;
368
369   if (NULL != p->th)
370     GNUNET_TRANSPORT_disconnect (p->th);
371
372   if (GNUNET_SYSERR == GNUNET_TESTING_peer_stop(p->peer))
373   {
374     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
375                      "Failed to stop peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
376     return GNUNET_SYSERR;
377   }
378
379   sleep (5);
380
381   /* restart */
382   if (GNUNET_SYSERR == GNUNET_TESTING_peer_start(p->peer))
383   {
384     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
385                      "Failed to restart peer %u (`%s')\n",
386                      p->no, GNUNET_i2s (&p->id));
387     return GNUNET_SYSERR;
388   }
389
390   GNUNET_assert (p->th != NULL);
391   GNUNET_assert (p->start_cb == NULL);
392   p->start_cb = restart_cb;
393   p->cb_cls = cb_cls;
394
395   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
396                                     &notify_receive,
397                                     &notify_connect,
398                                     &notify_disconnect);
399   GNUNET_assert (NULL != p->th);
400
401   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
402   GNUNET_assert (p->ghh != NULL);
403   return GNUNET_OK;
404 }
405
406
407 /**
408  * shutdown the given peer
409  * @param tth testing handle
410  * @param p the peer
411  */
412 void
413 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
414                                     struct PeerContext *p)
415 {
416   GNUNET_assert (p != NULL);
417   if (p->ghh != NULL)
418   {
419     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
420     p->ghh = NULL;
421   }
422   if (p->th != NULL)
423   {
424     GNUNET_TRANSPORT_disconnect (p->th);
425     p->th = NULL;
426   }
427
428   if (p->peer != NULL)
429   {
430     if (GNUNET_OK != GNUNET_TESTING_peer_stop (p->peer))
431     {
432       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
433                        "Testing lib failed to stop peer %u (`%s') \n", p->no,
434                        GNUNET_i2s (&p->id));
435     }
436     GNUNET_TESTING_peer_destroy (p->peer);
437     p->peer = NULL;
438   }
439
440   if (p->hello != NULL)
441   {
442     GNUNET_free (p->hello);
443     p->hello = NULL;
444   }
445   if (p->cfg != NULL)
446   {
447     GNUNET_CONFIGURATION_destroy (p->cfg);
448     p->cfg = NULL;
449   }
450   GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p);
451   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
452                    "Peer %u (`%s') stopped \n", p->no,
453                    GNUNET_i2s (&p->id));
454   GNUNET_free (p);
455 }
456
457
458 /**
459  * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
460  *
461  * Remarks: start_peer's notify_connect callback can be called before.
462  *
463  * @param tth transport testing handle
464  * @param p1 peer 1
465  * @param p2 peer 2
466  * @param cb the callback to call when both peers notified that they are connected
467  * @param cls callback cls
468  * @return a connect request handle
469  */
470 GNUNET_TRANSPORT_TESTING_ConnectRequest
471 GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
472                                         struct PeerContext *p1,
473                                         struct PeerContext *p2,
474                                         GNUNET_TRANSPORT_TESTING_connect_cb cb,
475                                         void *cls)
476 {
477   GNUNET_assert (tth != NULL);
478
479   struct ConnectingContext *cc =
480       GNUNET_malloc (sizeof (struct ConnectingContext));
481
482   GNUNET_assert (p1 != NULL);
483   GNUNET_assert (p2 != NULL);
484   cc->p1 = p1;
485   cc->p2 = p2;
486   cc->cb = cb;
487   if (cls != NULL)
488     cc->cb_cls = cls;
489   else
490     cc->cb_cls = cc;
491   cc->th_p1 = p1->th;
492   cc->th_p2 = p2->th;
493   GNUNET_assert (cc->th_p1 != NULL);
494   GNUNET_assert (cc->th_p2 != NULL);
495   GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc);
496   cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
497   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
498                    "New connect request %p\n", cc);
499
500   return cc;
501 }
502
503
504 /**
505  * Cancel the request to connect two peers
506  * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
507  *
508  * @param tth transport testing handle
509  * @param ccr a connect request handle
510  */
511 void
512 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
513                                                GNUNET_TRANSPORT_TESTING_handle
514                                                *tth,
515                                                GNUNET_TRANSPORT_TESTING_ConnectRequest
516                                                ccr)
517 {
518   struct ConnectingContext *cc = ccr;
519
520   GNUNET_assert (tth != NULL);
521
522   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
523                    "Canceling connect request %p!\n", cc);
524
525   if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
526     GNUNET_SCHEDULER_cancel (cc->tct);
527   cc->tct = GNUNET_SCHEDULER_NO_TASK;
528
529   GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc);
530   GNUNET_free (cc);
531 }
532
533
534 /**
535  * Clean up the transport testing
536  * @param tth transport testing handle
537  */
538 void
539 GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth)
540 {
541   struct ConnectingContext *cc = tth->cc_head;
542   struct ConnectingContext *ct = NULL;
543   struct PeerContext *p = tth->p_head;
544   struct PeerContext *t = NULL;
545
546   GNUNET_assert (tth != NULL);
547
548   while (cc != tth->cc_tail)
549   {
550     ct = cc->next;
551     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
552                      "Developer forgot to cancel connect request %p!\n", cc);
553     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
554     cc = ct;
555   }
556
557   while (p != NULL)
558   {
559     t = p->next;
560     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
561                      "Developer forgot to stop peer!\n");
562     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
563     p = t;
564   }
565
566   GNUNET_TESTING_system_destroy (tth->tl_system, GNUNET_YES);
567
568   GNUNET_free (tth);
569   tth = NULL;
570 }
571
572
573 /**
574  * Initialize the transport testing
575  * @return transport testing handle
576  */
577 struct GNUNET_TRANSPORT_TESTING_handle *
578 GNUNET_TRANSPORT_TESTING_init ()
579 {
580   struct GNUNET_TRANSPORT_TESTING_handle *tth;
581
582   /* prepare hostkeys */
583   tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle));
584
585   /* Init testing the testing lib */
586   tth->tl_system = GNUNET_TESTING_system_create ("transport-testing", NULL);
587   if (NULL == tth->tl_system)
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize testing library!\n"));
590     GNUNET_free (tth);
591     return NULL;
592   }
593
594   return tth;
595 }
596
597
598 /*
599  * Some utility functions
600  */
601
602 /**
603  * Removes all directory separators from absolute filename
604  * @param file the absolute file name, e.g. as found in argv[0]
605  * @return extracted file name, has to be freed by caller
606  */
607 static char *
608 extract_filename (const char *file)
609 {
610   char *pch = GNUNET_strdup (file);
611   char *backup = pch;
612   char *filename = NULL;
613   char *res;
614 #if WINDOWS
615   if ((strlen (pch) >= 3) && pch[1] == ':')
616   {
617     if (NULL != strstr (pch, "\\"))
618     {
619       pch = strtok (pch, "\\");
620       while (pch != NULL)
621       {
622         pch = strtok (NULL, "\\");
623         if (pch != NULL)
624           filename = pch;
625       }
626     }
627   }
628   if (filename != NULL)
629     pch = filename; /* If we miss the next condition, filename = pch will
630                      * not harm us.
631                      */
632 #endif
633   if (NULL != strstr (pch, "/"))
634   {
635     pch = strtok (pch, "/");
636     while (pch != NULL)
637     {
638       pch = strtok (NULL, "/");
639       if (pch != NULL)
640       {
641         filename = pch;
642       }
643     }
644   }
645   else
646     filename = pch;
647
648   res = GNUNET_strdup (filename);
649   GNUNET_free (backup);
650   return res;
651 }
652
653
654 /**
655  * Extracts the test filename from an absolute file name and removes the extension
656  * @param file absolute file name
657  * @param dest where to store result
658  */
659 void
660 GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest)
661 {
662   char *filename = extract_filename (file);
663   char *backup = filename;
664   char *dotexe;
665
666   if (filename == NULL)
667     goto fail;
668
669   /* remove "lt-" */
670   filename = strstr (filename, "tes");
671   if (filename == NULL)
672     goto fail;
673
674   /* remove ".exe" */
675   if (NULL != (dotexe = strstr (filename, ".exe")))
676     dotexe[0] = '\0';
677
678   goto suc;
679
680 fail:
681   (*dest) = NULL;
682   return;
683
684 suc:
685   /* create filename */
686   GNUNET_asprintf (dest, "%s", filename);
687   GNUNET_free (backup);
688 }
689
690
691 /**
692  * Extracts the filename from an absolute file name and removes the extension
693  * @param file absolute file name
694  * @param dest where to store result
695  */
696 void
697 GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest)
698 {
699   char *src = extract_filename (file);
700   char *split;
701
702   split = strstr (src, ".");
703   if (split != NULL)
704   {
705     split[0] = '\0';
706   }
707   GNUNET_asprintf (dest, "%s", src);
708   GNUNET_free (src);
709 }
710
711
712 /**
713  * Extracts the plugin name from an absolute file name and the test name
714  *
715  * @param file absolute file name
716  * @param test test name
717  * @param dest where to store result
718  */
719 void
720 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
721                                                const char *test, char **dest)
722 {
723   char *filename;
724   char *dotexe;
725   char *e = extract_filename (file);
726   char *t = extract_filename (test);
727
728   if (NULL == e)
729     goto fail;
730   /* remove "lt-" */
731   filename = strstr (e, "tes");
732   if (NULL == filename)
733     goto fail;
734   /* remove ".exe" */
735   if (NULL != (dotexe = strstr (filename, ".exe")))
736     dotexe[0] = '\0';
737
738   /* find last _ */
739   filename = strstr (filename, t);
740   if (NULL == filename)
741     goto fail;
742   /* copy plugin */
743   filename += strlen (t);
744   if ('\0' != *filename)
745     filename++;
746   GNUNET_asprintf (dest, "%s", filename);
747   goto suc;
748 fail:
749   (*dest) = NULL;
750 suc:
751   GNUNET_free (t);
752   GNUNET_free (e);
753 }
754
755
756 /**
757  * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
758  * if existing ".exe"-prefix and adds the peer-number
759  *
760  * @param file filename of the test, e.g. argv[0]
761  * @param dest where to write the filename
762  * @param count peer number
763  */
764 void
765 GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
766                                           int count)
767 {
768   char *filename = extract_filename (file);
769   char *backup = filename;
770   char *dotexe;
771
772   if (NULL == filename)
773     goto fail;
774   /* remove "lt-" */
775   filename = strstr (filename, "tes");
776   if (NULL == filename)
777     goto fail;
778   /* remove ".exe" */
779   if (NULL != (dotexe = strstr (filename, ".exe")))
780     dotexe[0] = '\0';
781   GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count);
782   GNUNET_free (backup);
783   return;
784 fail:
785   (*dest) = NULL;
786   GNUNET_free (backup);
787 }
788
789
790
791 /* end of transport-testing.c */