avoid asserting in API on timeout destruction
[oweals/gnunet.git] / src / cadet / test_cadet_single.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011 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 /**
22  * @file cadet/test_cadet_single.c
23  * @brief test cadet single: test of cadet channels with just one client
24  * @author Bartlomiej Polot
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dht_service.h"
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_cadet_service.h"
32
33 #define REPETITIONS 5
34 #define DATA_SIZE 35000
35
36 struct GNUNET_TESTING_Peer *me;
37
38 static struct GNUNET_CADET_Handle *cadet;
39
40 static struct GNUNET_CADET_Channel *ch1;
41
42 static struct GNUNET_CADET_Channel *ch2;
43
44 static int result;
45
46 static struct GNUNET_SCHEDULER_Task *abort_task;
47
48 static struct GNUNET_SCHEDULER_Task *connect_task;
49
50 static unsigned int repetition;
51
52 static struct GNUNET_CADET_TransmitHandle *nth;
53
54
55 /* forward declaration */
56 static size_t
57 do_send (void *cls, size_t size, void *buf);
58
59
60 /**
61  * Shutdown nicely
62  */
63 static void
64 do_shutdown (void *cls)
65 {
66   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
67   if (NULL != nth)
68   {
69     GNUNET_CADET_notify_transmit_ready_cancel (nth);
70     nth = NULL;
71   }
72   if (NULL != abort_task)
73   {
74     GNUNET_SCHEDULER_cancel (abort_task);
75     abort_task = NULL;
76   }
77   if (NULL != connect_task)
78   {
79     GNUNET_SCHEDULER_cancel (connect_task);
80     connect_task = NULL;
81   }
82   if (NULL != ch1)
83   {
84     GNUNET_CADET_channel_destroy (ch1);
85     ch1 = NULL;
86   }
87   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n");
88   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n");
89   if (NULL != cadet)
90   {
91     GNUNET_CADET_disconnect (cadet);
92     cadet = NULL;
93   }
94   else
95   {
96     GNUNET_break (0);
97   }
98 }
99
100
101 /**
102  * Something went wrong and timed out. Kill everything and set error flag
103  */
104 static void
105 do_abort (void *cls)
106 {
107   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
108   result = GNUNET_SYSERR;
109   abort_task = NULL;
110   GNUNET_SCHEDULER_shutdown ();
111 }
112
113
114 /**
115  * Function is called whenever a message is received.
116  *
117  * @param cls closure (set from GNUNET_CADET_connect)
118  * @param channel connection to the other end
119  * @param channel_ctx place to store local state associated with the channel
120  * @param message the actual message
121  *
122  * @return GNUNET_OK to keep the connection open,
123  *         GNUNET_SYSERR to close it (signal serious error)
124  */
125 static int
126 data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
127                void **channel_ctx,
128                const struct GNUNET_MessageHeader *message)
129 {
130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131               "Data callback! Repetition %u/%u\n",
132               repetition, REPETITIONS);
133   repetition = repetition + 1;
134   if (repetition < REPETITIONS)
135   {
136     struct GNUNET_CADET_Channel *my_channel;
137     if (repetition % 2 == 0)
138       my_channel = ch1;
139     else
140       my_channel = ch2;
141     nth = GNUNET_CADET_notify_transmit_ready (my_channel, GNUNET_NO,
142                                               GNUNET_TIME_UNIT_FOREVER_REL,
143                                               sizeof (struct GNUNET_MessageHeader)
144                                               + DATA_SIZE,
145                                               &do_send, NULL);
146     GNUNET_CADET_receive_done (channel);
147     return GNUNET_OK;
148   }
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All data OK. Destroying channel.\n");
150   GNUNET_CADET_channel_destroy (ch1);
151   ch1 = NULL;
152   return GNUNET_OK;
153 }
154
155
156 /**
157  * Method called whenever another peer has added us to a channel
158  * the other peer initiated.
159  *
160  * @param cls closure
161  * @param channel new handle to the channel
162  * @param initiator peer that started the channel
163  * @param port port number
164  * @param options channel option flags
165  * @return initial channel context for the channel
166  *         (can be NULL -- that's not an error)
167  */
168 static void *
169 inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel,
170                  const struct GNUNET_PeerIdentity *initiator,
171                  const struct GNUNET_HashCode *port,
172                  enum GNUNET_CADET_ChannelOption options)
173 {
174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175               "received incoming channel on port %s\n",
176               GNUNET_h2s (port));
177   ch2 = channel;
178   return NULL;
179 }
180
181
182 /**
183  * Function called whenever an inbound channel is destroyed.  Should clean up
184  * any associated state.
185  *
186  * @param cls closure (set from GNUNET_CADET_connect)
187  * @param channel connection to the other end (henceforth invalid)
188  * @param channel_ctx place where local state associated
189  *                   with the channel is stored
190  */
191 static void
192 channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
193              void *channel_ctx)
194 {
195   long id = (long) cls;
196
197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198               "incoming channel closed at peer %ld\n",
199               id);
200   if ( (REPETITIONS == repetition) &&
201        (channel == ch2) )
202   {
203     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204                 "everything fine! finishing!\n");
205     result = GNUNET_OK;
206     GNUNET_SCHEDULER_shutdown ();
207   }
208   if (channel == ch2)
209     ch2 = NULL;
210   if (channel == ch1)
211     ch1 = NULL;
212 }
213
214
215 /**
216  * Handler array for traffic received on peer1
217  */
218 static struct GNUNET_CADET_MessageHandler handlers1[] = {
219   {&data_callback, 1, 0},
220   {NULL, 0, 0}
221 };
222
223
224 /**
225  * Data send callback: fillbuffer with test packet.
226  *
227  * @param cls Closure (unused).
228  * @param size Buffer size.
229  * @param buf Buffer to fill.
230  *
231  * @return size of test packet.
232  */
233 static size_t
234 do_send (void *cls, size_t size, void *buf)
235 {
236   struct GNUNET_MessageHeader *m = buf;
237
238   nth = NULL;
239   if (NULL == buf)
240   {
241     GNUNET_break (0);
242     result = GNUNET_SYSERR;
243     return 0;
244   }
245   m->size = htons (sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
246   m->type = htons (1);
247   memset (&m[1], 0, DATA_SIZE);
248   GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
249   return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
250 }
251
252 /**
253  * Connect to other client and send data
254  *
255  * @param cls Closue (unused).
256  */
257 static void
258 do_connect (void *cls)
259 {
260   struct GNUNET_PeerIdentity id;
261   size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
262
263   connect_task = NULL;
264   GNUNET_TESTING_peer_get_identity (me, &id);
265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
266   ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, GC_u2h (1),
267                                      GNUNET_CADET_OPTION_DEFAULT);
268   nth = GNUNET_CADET_notify_transmit_ready (ch1, GNUNET_NO,
269                                             GNUNET_TIME_UNIT_FOREVER_REL,
270                                             size, &do_send, NULL);
271 }
272
273
274 /**
275  * Initialize framework and start test
276  *
277  * @param cls Closure (unused).
278  * @param cfg Configuration handle.
279  * @param peer Testing peer handle.
280  */
281 static void
282 run (void *cls,
283      const struct GNUNET_CONFIGURATION_Handle *cfg,
284      struct GNUNET_TESTING_Peer *peer)
285 {
286   me = peer;
287   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
288   abort_task =
289       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
290                                     (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
291                                     NULL);
292   cadet = GNUNET_CADET_connect (cfg,       /* configuration */
293                               (void *) 1L,     /* cls */
294                               &channel_end,      /* inbound end hndlr */
295                               handlers1); /* traffic handlers */
296   GNUNET_CADET_open_port (cadet, GC_u2h (1), &inbound_channel, (void *) 1L);
297
298
299   if (NULL == cadet)
300   {
301     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n");
302     result = GNUNET_SYSERR;
303     return;
304   }
305   connect_task
306     = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
307                                     &do_connect,
308                                     NULL);
309 }
310
311
312 /**
313  * Main
314  */
315 int
316 main (int argc, char *argv[])
317 {
318   result = GNUNET_NO;
319   if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
320                                     "test_cadet.conf",
321                                     &run, NULL))
322   {
323     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
324     return 2;
325   }
326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
327   return (result == GNUNET_OK) ? 0 : 1;
328 }
329
330 /* end of test_cadet_single.c */