50c297389126da68b1d3165a796ed25117b8b3e9
[oweals/gnunet.git] / src / transport / transport-testing.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file transport-testing.c
22  * @brief testing lib for transport service
23  * @author Matthias Wachs
24  * @author Christian Grothoff
25  */
26 #include "transport-testing.h"
27
28
29 #define LOG(kind,...) GNUNET_log_from(kind, "transport-testing", __VA_ARGS__)
30
31
32 static struct GNUNET_TRANSPORT_TESTING_PeerContext *
33 find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
34                    const struct GNUNET_PeerIdentity *peer)
35 {
36   struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
37
38   for (t = tth->p_head; NULL != t; t = t->next)
39     if (0 == memcmp (&t->id,
40                      peer,
41                      sizeof (struct GNUNET_PeerIdentity)))
42       return t;
43   return NULL;
44 }
45
46
47 /**
48  * Find any connecting context matching the given pair of peers.
49  *
50  * @param p1 first peer
51  * @param p2 second peer
52  * @param cb function to call 
53  * @param cb_cls closure for @a cb
54  */
55 void
56 GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
57                                                   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
58                                                   GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
59                                                   void *cb_cls)
60 {
61   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
62   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
63   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
64
65   for (cc = tth->cc_head; NULL != cc; cc = ccn)
66   {
67     ccn = cc->next;
68     if ( (cc->p1 == p1) &&
69          (cc->p2 == p2) ) 
70       cb (cb_cls,
71           cc);
72   }
73 }
74
75
76 static void
77 set_p1c (void *cls,   
78          struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
79 {
80   cx->p1_c = GNUNET_YES;
81 }
82
83
84 static void
85 set_p2c (void *cls,   
86          struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
87 {
88   cx->p2_c = GNUNET_YES;
89 }
90
91
92 static void
93 clear_p1c (void *cls,   
94            struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
95 {
96   cx->p1_c = GNUNET_NO;
97 }
98
99
100 static void
101 clear_p2c (void *cls,   
102          struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
103 {
104   cx->p2_c = GNUNET_NO;
105 }
106
107
108 static void
109 notify_connect (void *cls,
110                 const struct GNUNET_PeerIdentity *peer)
111 {
112   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
113   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
114   char *p2_s;
115   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
116   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
117   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
118
119   p2 = find_peer_context (p->tth,
120                           peer);
121   if (NULL != p->nc)
122     p->nc (p->cb_cls,
123            peer);
124
125   if (p2 != NULL)
126     GNUNET_asprintf (&p2_s,
127                      "%u (`%s')",
128                      p2->no,
129                      GNUNET_i2s (&p2->id));
130   else
131     GNUNET_asprintf (&p2_s,
132                      "`%s'",
133                      GNUNET_i2s (peer));
134   LOG (GNUNET_ERROR_TYPE_DEBUG,
135        "Peers %s connected to peer %u (`%s')\n",
136        p2_s,
137        p->no,
138        GNUNET_i2s (&p->id));
139   GNUNET_free (p2_s);
140   /* update flags in connecting contexts */
141   GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
142                                                     p2,
143                                                     &set_p1c,
144                                                     NULL);
145   GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
146                                                     p,
147                                                     &set_p2c,
148                                                     NULL);
149   /* update set connected flag for all requests */
150   for (cc = tth->cc_head; NULL != cc; cc = cc->next)
151   {
152     if (GNUNET_YES == cc->connected)
153       continue;
154     if ( (GNUNET_YES == cc->p1_c) &&
155          (GNUNET_YES == cc->p2_c) )
156     {
157       cc->connected = GNUNET_YES;
158       /* stop trying to connect */
159       if (NULL != cc->tct)
160       {
161         GNUNET_SCHEDULER_cancel (cc->tct);
162         cc->tct = NULL;
163       }
164       if (NULL != cc->oh)
165       {
166         GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
167         cc->oh = NULL;
168       }
169       if (NULL != cc->ats_sh)
170       {
171         GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
172         cc->ats_sh = NULL;
173       }
174     }
175   }
176   /* then notify application */
177   for (cc = tth->cc_head; NULL != cc; cc = ccn)
178   {
179     ccn = cc->next;
180     if ( (GNUNET_YES == cc->connected) &&
181          (NULL != cc->cb) )
182     {
183       cc->cb (cc->cb_cls);
184       cc->cb = NULL; /* only notify once! */
185     }
186   }
187 }
188
189
190 /**
191  * Offer the current HELLO of P2 to P1.
192  *
193  * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
194  */
195 static void
196 offer_hello (void *cls);
197
198
199 static void
200 notify_disconnect (void *cls,
201                    const struct GNUNET_PeerIdentity *peer)
202 {
203   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
204   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
205   char *p2_s;
206   /* Find PeerContext */
207   int no = 0;
208   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
209   struct TRANSPORT_TESTING_SendJob *sj;
210   struct TRANSPORT_TESTING_SendJob *sjn;
211   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
212   
213   p2 = find_peer_context (p->tth,
214                           peer);
215   no = p->no;
216   if (NULL != p2)
217     GNUNET_asprintf (&p2_s,
218                      "%u (`%s')",
219                      p2->no,
220                      GNUNET_i2s (&p2->id));
221   else
222     GNUNET_asprintf (&p2_s,
223                      "`%s'",
224                      GNUNET_i2s (peer));
225   LOG (GNUNET_ERROR_TYPE_DEBUG,
226        "Peers %s disconnected from peer %u (`%s')\n",
227        p2_s,
228        no,
229        GNUNET_i2s (&p->id));
230   GNUNET_free (p2_s);
231   /* notify about disconnect */
232   if (NULL != p->nd)
233     p->nd (p->cb_cls,
234            peer);
235   if (NULL == p2)
236     return;
237   /* abort all transmissions this disconnected pair is involved in */
238   for (sj = tth->sj_head; NULL != sj; sj = sjn)
239   {
240     sjn = sj->next;
241     if ( ( (sj->sender == p2) &&
242            (sj->receiver == p) ) ||
243          ( (sj->receiver == p2) &&
244            (sj->sender == p) ) )
245     {
246       GNUNET_CONTAINER_DLL_remove (tth->sj_head,
247                                    tth->sj_tail,
248                                    sj);
249       GNUNET_TRANSPORT_notify_transmit_ready_cancel (sj->th);
250       GNUNET_free (sj);
251     }
252   }
253   /* update set connected flags for all requests */
254   GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
255                                                     p2,
256                                                     &clear_p1c,
257                                                     NULL);
258   GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
259                                                     p,
260                                                     &clear_p2c,
261                                                     NULL);
262   /* resume connectivity requests as necessary */
263   for (cc = tth->cc_head; NULL != cc; cc = cc->next)
264   {
265     if (GNUNET_NO == cc->connected)
266       continue;
267     if ( (GNUNET_YES != cc->p1_c) ||
268          (GNUNET_YES != cc->p2_c) )
269     {
270       cc->connected = GNUNET_NO;
271       /* start trying to connect */
272       if ( (NULL == cc->tct) &&
273            (NULL == cc->oh) )
274         cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
275                                             cc);
276       if (NULL == cc->ats_sh)
277         cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
278                                                       &p2->id,
279                                                       1);
280     }
281   }
282 }
283
284
285 static void
286 notify_receive (void *cls,
287                 const struct GNUNET_PeerIdentity *peer,
288                 const struct GNUNET_MessageHeader *message)
289 {
290   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
291
292   if (NULL == p)
293     return;
294   if (NULL != p->rec)
295     p->rec (p->cb_cls,
296             peer,
297             message);
298 }
299
300
301 static void
302 get_hello (void *cb_cls,
303            const struct GNUNET_MessageHeader *message)
304 {
305   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
306   struct GNUNET_PeerIdentity hello_id;
307
308   GNUNET_assert (GNUNET_OK ==
309                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message,
310                                       &hello_id));
311   GNUNET_assert (0 == memcmp (&hello_id,
312                               &p->id,
313                               sizeof (hello_id)));
314   GNUNET_free_non_null (p->hello);
315   p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
316
317   if (NULL != p->start_cb)
318   {
319     LOG (GNUNET_ERROR_TYPE_DEBUG,
320          "Peer %u (`%s') successfully started\n",
321          p->no,
322          GNUNET_i2s (&p->id));
323     p->start_cb (p,
324                  p->start_cb_cls);
325     p->start_cb = NULL;
326   }
327 }
328
329
330 /**
331  * Start a peer with the given configuration
332  * @param tth the testing handle
333  * @param cfgname configuration file
334  * @param peer_id a unique number to identify the peer
335  * @param rec receive callback
336  * @param nc connect callback
337  * @param nd disconnect callback
338  * @param cb_cls closure for callback
339  * @param start_cb start callback
340  * @param start_cb_cls closure for callback
341  * @return the peer context
342  */
343 struct GNUNET_TRANSPORT_TESTING_PeerContext *
344 GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
345                                      const char *cfgname,
346                                      int peer_id,
347                                      GNUNET_TRANSPORT_ReceiveCallback rec,
348                                      GNUNET_TRANSPORT_NotifyConnect nc,
349                                      GNUNET_TRANSPORT_NotifyDisconnect nd,
350                                      void *cb_cls,
351                                      GNUNET_TRANSPORT_TESTING_StartCallback start_cb,
352                                      void *start_cb_cls)
353 {
354   char *emsg = NULL;
355   struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
356   struct GNUNET_PeerIdentity *dummy;
357
358   if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
359   {
360     LOG (GNUNET_ERROR_TYPE_ERROR,
361          "File not found: `%s'\n",
362          cfgname);
363     return NULL;
364   }
365
366   p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
367   p->tth = tth;
368   p->nc = nc;
369   p->nd = nd;
370   p->rec = rec;
371   if (NULL != cb_cls)
372     p->cb_cls = cb_cls;
373   else
374     p->cb_cls = p;
375   p->start_cb = start_cb;
376   p->start_cb_cls = start_cb_cls;
377   GNUNET_CONTAINER_DLL_insert (tth->p_head,
378                                tth->p_tail,
379                                p);
380
381   /* Create configuration and call testing lib to modify it */
382   p->cfg = GNUNET_CONFIGURATION_create ();
383   GNUNET_assert (GNUNET_OK ==
384                  GNUNET_CONFIGURATION_load (p->cfg, cfgname));
385   if (GNUNET_SYSERR ==
386       GNUNET_TESTING_configuration_create (tth->tl_system,
387                                            p->cfg))
388   {
389     LOG (GNUNET_ERROR_TYPE_ERROR,
390          "Testing library failed to create unique configuration based on `%s'\n",
391          cfgname);
392     GNUNET_CONFIGURATION_destroy (p->cfg);
393     GNUNET_free (p);
394     return NULL;
395   }
396
397   p->no = peer_id;
398   /* Configure peer with configuration */
399   p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
400                                            p->cfg,
401                                            p->no,
402                                            NULL,
403                                            &emsg);
404   if (NULL == p->peer)
405   {
406     LOG (GNUNET_ERROR_TYPE_ERROR,
407          "Testing library failed to create unique configuration based on `%s': `%s'\n",
408          cfgname,
409          emsg);
410     GNUNET_TRANSPORT_TESTING_stop_peer (p);
411     GNUNET_free_non_null (emsg);
412     return NULL;
413   }
414   GNUNET_free_non_null (emsg);
415   if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
416   {
417     LOG (GNUNET_ERROR_TYPE_ERROR,
418          "Testing library failed to create unique configuration based on `%s'\n",
419          cfgname);
420     GNUNET_TRANSPORT_TESTING_stop_peer (p);
421     return NULL;
422   }
423
424   memset (&dummy,
425           '\0',
426           sizeof (dummy));
427   GNUNET_TESTING_peer_get_identity (p->peer,
428                                     &p->id);
429   if (0 == memcmp (&dummy,
430                    &p->id,
431                    sizeof (struct GNUNET_PeerIdentity)))
432   {
433     LOG (GNUNET_ERROR_TYPE_ERROR,
434          "Testing library failed to obtain peer identity for peer %u\n",
435          p->no);
436     GNUNET_TRANSPORT_TESTING_stop_peer (p);
437     return NULL;
438   }
439   LOG (GNUNET_ERROR_TYPE_DEBUG,
440        "Peer %u configured with identity `%s'\n",
441        p->no,
442        GNUNET_i2s_full (&p->id));
443
444   p->th = GNUNET_TRANSPORT_connect (p->cfg,
445                                     NULL,
446                                     p,
447                                     &notify_receive,
448                                     &notify_connect,
449                                     &notify_disconnect);
450   if (NULL == p->th)
451   {
452     LOG (GNUNET_ERROR_TYPE_ERROR,
453          "Failed to connect to transport service for peer `%s': `%s'\n",
454          cfgname,
455          emsg);
456     GNUNET_TRANSPORT_TESTING_stop_peer (p);
457     return NULL;
458   }
459   p->ats = GNUNET_ATS_connectivity_init (p->cfg);
460   if (NULL == p->ats)
461   {
462     LOG (GNUNET_ERROR_TYPE_ERROR,
463          "Failed to connect to ATS service for peer `%s': `%s'\n",
464          cfgname,
465          emsg);
466     GNUNET_TRANSPORT_TESTING_stop_peer (p);
467     return NULL;
468   }
469   p->ghh = GNUNET_TRANSPORT_get_hello (p->cfg,
470                                        &get_hello,
471                                        p);
472   GNUNET_assert (p->ghh != NULL);
473   return p;
474 }
475
476
477 /**
478  * Stops and restarts the given peer, sleeping (!) for 5s in between.
479  *
480  * @param p the peer
481  * @param restart_cb callback to call when restarted
482  * @param restart_cb_cls callback closure
483  * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
484  */
485 int
486 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
487                                        GNUNET_TRANSPORT_TESTING_StartCallback restart_cb,
488                                        void *restart_cb_cls)
489 {
490   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
491   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
492  
493   /* shutdown */
494   LOG (GNUNET_ERROR_TYPE_DEBUG,
495        "Stopping peer %u (`%s')\n",
496        p->no,
497        GNUNET_i2s (&p->id));
498   if (NULL != p->ghh)
499   {
500     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
501     p->ghh = NULL;
502   }
503   if (NULL != p->th)
504   {
505     GNUNET_TRANSPORT_disconnect (p->th);
506     p->th = NULL;
507   }
508   for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
509   {
510     ccn = cc->next;
511     if ( (cc->p1 == p) ||
512          (cc->p2 == p) )
513       GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
514   }
515   if (NULL != p->ats)
516   {
517     GNUNET_ATS_connectivity_done (p->ats);
518     p->ats = NULL;
519   }
520   if (GNUNET_SYSERR ==
521       GNUNET_TESTING_peer_stop (p->peer))
522   {
523     LOG (GNUNET_ERROR_TYPE_ERROR,
524          "Failed to stop peer %u (`%s')\n",
525          p->no,
526          GNUNET_i2s (&p->id));
527     return GNUNET_SYSERR;
528   }
529
530   sleep (5); // YUCK!
531
532   LOG (GNUNET_ERROR_TYPE_DEBUG,
533        "Restarting peer %u (`%s')\n",
534        p->no,
535        GNUNET_i2s (&p->id));
536   /* restart */
537   if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
538   {
539     LOG (GNUNET_ERROR_TYPE_ERROR,
540          "Failed to restart peer %u (`%s')\n",
541          p->no,
542          GNUNET_i2s (&p->id));
543     return GNUNET_SYSERR;
544   }
545
546   GNUNET_assert (NULL == p->start_cb);
547   p->start_cb = restart_cb;
548   p->start_cb_cls = restart_cb_cls;
549
550   p->th = GNUNET_TRANSPORT_connect (p->cfg,
551                                     NULL,
552                                     p,
553                                     &notify_receive,
554                                     &notify_connect,
555                                     &notify_disconnect);
556   GNUNET_assert (NULL != p->th);
557   p->ats = GNUNET_ATS_connectivity_init (p->cfg);
558   p->ghh = GNUNET_TRANSPORT_get_hello (p->cfg,
559                                        &get_hello,
560                                        p);
561   GNUNET_assert (NULL != p->ghh);
562   return GNUNET_OK;
563 }
564
565
566 /**
567  * Shutdown the given peer
568  *
569  * @param p the peer
570  */
571 void
572 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext *p)
573 {
574   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
575   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
576   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
577
578   for (cc = tth->cc_head; NULL != cc; cc = ccn)
579   {
580     ccn = cc->next;
581     if ( (cc->p1 == p) ||
582          (cc->p2 == p) )
583       GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
584   }
585   if (NULL != p->ghh)
586   {
587     GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
588     p->ghh = NULL;
589   }
590   if (NULL != p->th)
591   {
592     GNUNET_TRANSPORT_disconnect (p->th);
593     p->th = NULL;
594   }
595   if (NULL != p->peer)
596   {
597     if (GNUNET_OK !=
598         GNUNET_TESTING_peer_stop (p->peer))
599     {
600       LOG (GNUNET_ERROR_TYPE_DEBUG,
601            "Testing lib failed to stop peer %u (`%s')\n",
602            p->no,
603            GNUNET_i2s (&p->id));
604     }
605     GNUNET_TESTING_peer_destroy (p->peer);
606     p->peer = NULL;
607   }
608   if (NULL != p->ats)
609   {
610     GNUNET_ATS_connectivity_done (p->ats);
611     p->ats = NULL;
612   }
613   if (NULL != p->hello)
614   {
615     GNUNET_free (p->hello);
616     p->hello = NULL;
617   }
618   if (NULL != p->cfg)
619   {
620     GNUNET_CONFIGURATION_destroy (p->cfg);
621     p->cfg = NULL;
622   }
623   GNUNET_CONTAINER_DLL_remove (tth->p_head,
624                                tth->p_tail,
625                                p);
626   LOG (GNUNET_ERROR_TYPE_DEBUG,
627        "Peer %u (`%s') stopped\n",
628        p->no,
629        GNUNET_i2s (&p->id));
630   GNUNET_free (p);
631 }
632
633
634 /**
635  * Function called after the HELLO was passed to the
636  * transport service.
637  */
638 static void
639 hello_offered (void *cls)
640 {
641   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
642
643   cc->oh = NULL;
644   cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
645                                           &offer_hello,
646                                           cc);
647 }
648
649
650 /**
651  * Offer the current HELLO of P2 to P1.
652  *
653  * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
654  */
655 static void
656 offer_hello (void *cls)
657 {
658   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
659   struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
660   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
661
662   cc->tct = NULL;
663   {
664     char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
665
666     LOG (GNUNET_ERROR_TYPE_DEBUG,
667          "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
668          p1->no,
669          GNUNET_i2s (&p1->id),
670          p2->no,
671          p2_s,
672          GNUNET_HELLO_size (cc->p2->hello));
673     GNUNET_free (p2_s);
674   }
675
676   if (NULL != cc->oh)
677     GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
678   cc->oh =
679     GNUNET_TRANSPORT_offer_hello (cc->p1->cfg,
680                                   (const struct GNUNET_MessageHeader *) cc->p2->hello,
681                                   &hello_offered,
682                                   cc);
683 }
684
685
686 /**
687  * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
688  *
689  * Remarks: start_peer's notify_connect callback can be called before.
690  *
691  * @param tth transport testing handle
692  * @param p1 peer 1
693  * @param p2 peer 2
694  * @param cb the callback to call when both peers notified that they are connected
695  * @param cls callback cls
696  * @return a connect request handle
697  */
698 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
699 GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
700                                         struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
701                                         GNUNET_SCHEDULER_TaskCallback cb,
702                                         void *cls)
703 {
704   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
705   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
706
707   cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
708   cc->p1 = p1;
709   cc->p2 = p2;
710   cc->cb = cb;
711   if (NULL != cls)
712     cc->cb_cls = cls;
713   else
714     cc->cb_cls = cc;
715   GNUNET_CONTAINER_DLL_insert (tth->cc_head,
716                                tth->cc_tail,
717                                cc);
718   cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
719                                       cc);
720   cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
721                                                 &p2->id,
722                                                 1);
723   LOG (GNUNET_ERROR_TYPE_DEBUG,
724        "New connect request %p\n",
725        cc);
726   return cc;
727 }
728
729
730 /**
731  * Cancel the request to connect two peers
732  * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
733  *
734  * @param tth transport testing handle
735  * @param cc a connect request handle
736  */
737 void
738 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc)
739 {
740   struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
741
742   LOG (GNUNET_ERROR_TYPE_DEBUG,
743        "Canceling connect request!\n");
744   if (NULL != cc->tct)
745   {
746     GNUNET_SCHEDULER_cancel (cc->tct);
747     cc->tct = NULL;
748   }
749   if (NULL != cc->oh)
750   {
751     GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
752     cc->oh = NULL;
753   }
754   if (NULL != cc->ats_sh)
755   {
756     GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
757     cc->ats_sh = NULL;
758   }
759   GNUNET_CONTAINER_DLL_remove (tth->cc_head,
760                                tth->cc_tail,
761                                cc);
762   GNUNET_free (cc);
763 }
764
765
766 /**
767  * Clean up the transport testing
768  *
769  * @param tth transport testing handle
770  */
771 void
772 GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
773 {
774   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
775   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
776   struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
777   struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
778
779   if (NULL == tth)
780     return;
781   cc = tth->cc_head;
782   while (NULL != cc)
783   {
784     ct = cc->next;
785     LOG (GNUNET_ERROR_TYPE_ERROR,
786          "Developer forgot to cancel connect request!\n");
787     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
788     cc = ct;
789   }
790   p = tth->p_head;
791   while (NULL != p)
792   {
793     t = p->next;
794     LOG (GNUNET_ERROR_TYPE_ERROR,
795          "Developer forgot to stop peer!\n");
796     GNUNET_TRANSPORT_TESTING_stop_peer (p);
797     p = t;
798   }
799   GNUNET_TESTING_system_destroy (tth->tl_system,
800                                  GNUNET_YES);
801
802   GNUNET_free (tth);
803 }
804
805
806 /**
807  * Initialize the transport testing
808  *
809  * @return transport testing handle
810  */
811 struct GNUNET_TRANSPORT_TESTING_Handle *
812 GNUNET_TRANSPORT_TESTING_init ()
813 {
814   struct GNUNET_TRANSPORT_TESTING_Handle *tth;
815
816   tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
817   tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
818                                                  NULL,
819                                                  NULL,
820                                                  NULL);
821   if (NULL == tth->tl_system)
822   {
823     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824                 "Failed to initialize testing library!\n");
825     GNUNET_free (tth);
826     return NULL;
827   }
828   return tth;
829 }
830
831 /* end of transport-testing.c */