indentation
[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 struct ConnectingContext
31 {
32   struct PeerContext *p1;
33   struct PeerContext *p2;
34   GNUNET_SCHEDULER_TaskIdentifier tct;
35   GNUNET_TRANSPORT_TESTING_connect_cb cb;
36   void *cb_cls;
37
38   struct GNUNET_TRANSPORT_Handle *th_p1;
39   struct GNUNET_TRANSPORT_Handle *th_p2;
40   int p1_c;
41   int p2_c;
42 };
43
44 static void
45 exchange_hello_last (void *cb_cls, const struct GNUNET_MessageHeader *message);
46 static void
47 exchange_hello (void *cb_cls, const struct GNUNET_MessageHeader *message);
48
49 static void
50 notify_connect_internal (void *cls,
51                          const struct GNUNET_PeerIdentity *peer,
52                          const struct GNUNET_TRANSPORT_ATS_Information *ats,
53                          uint32_t ats_count)
54 {
55   struct ConnectingContext *cc = cls;
56
57   GNUNET_assert (cc != NULL);
58
59   if (0 ==
60       memcmp (&(*peer).hashPubKey, &cc->p1->id.hashPubKey,
61               sizeof (GNUNET_HashCode)))
62   {
63     if (cc->p1_c == GNUNET_NO)
64       cc->p1_c = GNUNET_YES;
65   }
66   if (0 ==
67       memcmp (&(*peer).hashPubKey, &cc->p2->id.hashPubKey,
68               sizeof (GNUNET_HashCode)))
69   {
70     if (cc->p2_c == GNUNET_NO)
71       cc->p2_c = GNUNET_YES;
72   }
73
74   if ((cc->p2_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
75   {
76     /* clean up */
77     GNUNET_TRANSPORT_get_hello_cancel (cc->th_p2, &exchange_hello_last, cc);
78     GNUNET_TRANSPORT_get_hello_cancel (cc->th_p1, &exchange_hello, cc);
79
80     if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
81       GNUNET_SCHEDULER_cancel (cc->tct);
82
83     cc->tct = GNUNET_SCHEDULER_NO_TASK;
84
85     GNUNET_TRANSPORT_disconnect (cc->th_p1);
86     GNUNET_TRANSPORT_disconnect (cc->th_p2);
87
88     if (cc->cb != NULL)
89       cc->cb (cc->p1, cc->p2, cc->cb_cls);
90
91     GNUNET_free (cc);
92   }
93 }
94
95 static void
96 notify_connect (void *cls,
97                 const struct GNUNET_PeerIdentity *peer,
98                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
99                 uint32_t ats_count)
100 {
101   struct PeerContext *p = cls;
102
103   if (p == NULL)
104     return;
105   if (p->nc != NULL)
106     p->nc (p->cb_cls, peer, ats, ats_count);
107 }
108
109 static void
110 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
111 {
112   struct PeerContext *p = cls;
113
114   if (p == NULL)
115     return;
116   if (p->nd != NULL)
117     p->nd (p->cb_cls, peer);
118 }
119
120 static void
121 notify_receive (void *cls,
122                 const struct GNUNET_PeerIdentity *peer,
123                 const struct GNUNET_MessageHeader *message,
124                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
125                 uint32_t ats_count)
126 {
127   struct PeerContext *p = cls;
128
129   if (p == NULL)
130     return;
131   if (p->rec != NULL)
132     p->rec (p->cb_cls, peer, message, ats, ats_count);
133 }
134
135
136 static void
137 exchange_hello_last (void *cb_cls, const struct GNUNET_MessageHeader *message)
138 {
139   struct ConnectingContext *cc = cb_cls;
140   struct PeerContext *me = cc->p2;
141
142   //struct PeerContext *p1 = cc->p1;
143
144   GNUNET_assert (message != NULL);
145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146               "Exchanging HELLO of size %d with peer (%s)!\n",
147               (int) GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *)
148                                        message), GNUNET_i2s (&me->id));
149   GNUNET_assert (GNUNET_OK ==
150                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
151                                       message, &me->id));
152   GNUNET_TRANSPORT_offer_hello (cc->th_p1, message, NULL, NULL);
153 }
154
155
156 static void
157 exchange_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
158 {
159   struct ConnectingContext *cc = cb_cls;
160   struct PeerContext *me = cc->p1;
161
162   //struct PeerContext *p2 = cc->p2;
163
164   GNUNET_assert (message != NULL);
165   GNUNET_assert (GNUNET_OK ==
166                  GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
167                                       message, &me->id));
168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
169               "Exchanging HELLO of size %d from peer %s!\n",
170               (int) GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *)
171                                        message), GNUNET_i2s (&me->id));
172   GNUNET_TRANSPORT_offer_hello (cc->th_p2, message, NULL, NULL);
173 }
174
175 static void
176 try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
177 {
178   struct ConnectingContext *cc = cls;
179   struct PeerContext *p1 = cc->p1;
180   struct PeerContext *p2 = cc->p2;
181
182   cc->tct = GNUNET_SCHEDULER_NO_TASK;
183   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
184     return;
185
186   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking peers to connect...\n");
187   /* FIXME: 'pX.id' may still be all-zeros here... */
188   GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id);
189   GNUNET_TRANSPORT_try_connect (cc->th_p2, &p1->id);
190
191   cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
192                                           &try_connect, cc);
193 }
194
195
196 /**
197  * Start a peer with the given configuration
198  * @param rec receive callback
199  * @param nc connect callback
200  * @param nd disconnect callback
201  * @param cb_cls closure for callback
202  * @return the peer context
203  */
204 struct PeerContext *
205 GNUNET_TRANSPORT_TESTING_start_peer (const char *cfgname,
206                                      GNUNET_TRANSPORT_ReceiveCallback rec,
207                                      GNUNET_TRANSPORT_NotifyConnect nc,
208                                      GNUNET_TRANSPORT_NotifyDisconnect nd,
209                                      void *cb_cls)
210 {
211   struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
212
213   p->cfg = GNUNET_CONFIGURATION_create ();
214
215   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
216   if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
217     GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", "SERVICEHOME",
218                                            &p->servicehome);
219   if (NULL != p->servicehome)
220     GNUNET_DISK_directory_remove (p->servicehome);
221   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
222                                          "gnunet-service-arm", "-c", cfgname,
223 #if VERBOSE_PEERS
224                                          "-L", "DEBUG",
225 #else
226                                          "-L", "ERROR",
227 #endif
228                                          NULL);
229   p->nc = nc;
230   p->nd = nd;
231   p->rec = rec;
232   if (cb_cls != NULL)
233     p->cb_cls = cb_cls;
234   else
235     p->cb_cls = p;
236
237   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL,
238                                     p,
239                                     &notify_receive,
240                                     &notify_connect, &notify_disconnect);
241   GNUNET_assert (p->th != NULL);
242   return p;
243 }
244
245 /**
246  * shutdown the given peer
247  * @param p the peer
248  */
249 void
250 GNUNET_TRANSPORT_TESTING_stop_peer (struct PeerContext *p)
251 {
252   if (p->th != NULL)
253     GNUNET_TRANSPORT_disconnect (p->th);
254
255   if (NULL != p->arm_proc)
256   {
257     if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
258       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
259     GNUNET_OS_process_wait (p->arm_proc);
260     GNUNET_OS_process_close (p->arm_proc);
261     p->arm_proc = NULL;
262   }
263   GNUNET_CONFIGURATION_destroy (p->cfg);
264   if (p->servicehome != NULL)
265   {
266     GNUNET_DISK_directory_remove (p->servicehome);
267     GNUNET_free (p->servicehome);
268   }
269   GNUNET_free (p);
270 }
271
272 /**
273  * Connect the two given peers and call the callback when both peers report the
274  * inbound connect. Remarks: start_peer's notify_connect callback can be called
275  * before.
276  * @param p1 peer 1
277  * @param p2 peer 2
278  * @param cb the callback to call
279  * @param cb_cls callback cls
280  */
281 void
282 GNUNET_TRANSPORT_TESTING_connect_peers (struct PeerContext *p1,
283                                         struct PeerContext *p2,
284                                         GNUNET_TRANSPORT_TESTING_connect_cb cb,
285                                         void *cb_cls)
286 {
287   struct ConnectingContext *cc =
288       GNUNET_malloc (sizeof (struct ConnectingContext));
289
290   GNUNET_assert (p1 != NULL);
291   GNUNET_assert (p2 != NULL);
292
293   cc->p1 = p1;
294   cc->p2 = p2;
295
296   cc->cb = cb;
297   cc->cb_cls = cb_cls;
298
299   cc->th_p1 = GNUNET_TRANSPORT_connect (cc->p1->cfg, NULL,
300                                         cc,
301                                         NULL, &notify_connect_internal, NULL);
302
303   cc->th_p2 = GNUNET_TRANSPORT_connect (cc->p2->cfg, NULL,
304                                         cc,
305                                         NULL, &notify_connect_internal, NULL);
306
307   GNUNET_assert (cc->th_p1 != NULL);
308   GNUNET_assert (cc->th_p2 != NULL);
309
310   GNUNET_TRANSPORT_get_hello (cc->th_p1, &exchange_hello, cc);
311   GNUNET_TRANSPORT_get_hello (cc->th_p2, &exchange_hello_last, cc);
312
313   cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
314 }
315
316
317
318 /* end of transport_testing.h */