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