more refactoring of tests for new send API
[oweals/gnunet.git] / src / transport / transport-testing-send.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 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-send.c
22  * @brief convenience transmission function for tests
23  * @author Christian Grothoff
24  */
25 #include "transport-testing.h"
26
27 /**
28  * Acceptable transmission delay.
29  */
30 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
31
32
33 static size_t
34 notify_ready (void *cls,
35               size_t size,
36               void *buf)
37
38   struct TRANSPORT_TESTING_SendJob *sj = cls;
39   struct GNUNET_TRANSPORT_TESTING_PeerContext *sender = sj->sender;
40   struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver = sj->receiver;
41   struct GNUNET_TRANSPORT_TESTING_Handle *tth = sender->tth;
42   uint16_t msize = sj->msize;
43   struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
44
45   sj->th = NULL;
46   GNUNET_CONTAINER_DLL_remove (tth->sj_head,
47                                tth->sj_tail,
48                                sj);
49   if (NULL == buf)
50   {
51     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
52                 "Timeout occurred while waiting for transmit_ready\n");
53     GNUNET_SCHEDULER_shutdown ();
54     GNUNET_free (sj);
55     return 0;
56   }
57
58   GNUNET_assert (size >= msize);
59   if (NULL != buf)
60   {
61     memset (buf, sj->num, msize);
62     test = buf;
63     test->header.size = htons (msize);
64     test->header.type = htons (sj->mtype);
65     test->num = htonl (sj->num);
66   }
67
68   {
69     char *ps = GNUNET_strdup (GNUNET_i2s (&sender->id));
70
71     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72                 "Sending message %u from %u (%s) with type %u and size %u bytes to peer %u (%s)\n",
73                 (unsigned int) sj->num,
74                 sender->no,
75                 ps,
76                 sj->mtype,
77                 msize,
78                 receiver->no,
79                 GNUNET_i2s (&receiver->id));
80     GNUNET_free (ps);
81   }
82   if (NULL != sj->cont)
83     GNUNET_SCHEDULER_add_now (sj->cont,
84                               sj->cont_cls);
85   GNUNET_free (sj);
86   return msize;
87 }
88
89
90 /**
91  * Return @a cx in @a cls.
92  */
93 static void
94 find_cr (void *cls,   
95          struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
96 {
97   struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
98
99   if (GNUNET_NO == cx->connected)
100     return;
101   *cr = cx;
102 }
103
104
105 /**
106  * Send a test message of type @a mtype and size @a msize from
107  * peer @a sender to peer @a receiver.  The peers should be
108  * connected when this function is called.
109  *
110  * @param sender the sending peer
111  * @param receiver the receiving peer
112  * @param mtype message type to use
113  * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
114  * @param num unique message number
115  * @param cont continuation to call after transmission
116  * @param cont_cls closure for @a cont
117  * @return #GNUNET_OK if message was queued,
118  *         #GNUNET_NO if peers are not connected
119  *         #GNUNET_SYSERR if @a msize is illegal
120  */
121 int
122 GNUNET_TRANSPORT_TESTING_send (struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
123                                struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
124                                uint16_t mtype,
125                                uint16_t msize,
126                                uint32_t num,
127                                GNUNET_SCHEDULER_TaskCallback cont,
128                                void *cont_cls)
129 {
130   struct GNUNET_TRANSPORT_TESTING_Handle *tth = sender->tth;
131   struct TRANSPORT_TESTING_SendJob *sj;
132   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
133
134   if (msize < sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage))
135   {
136     GNUNET_break (0);
137     return GNUNET_SYSERR;
138   }
139   cr = NULL;
140   GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
141                                                     receiver,
142                                                     &find_cr,
143                                                     &cr);
144   if (NULL == cr)
145     GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
146                                                       sender,
147                                                       &find_cr,
148                                                       &cr);
149   if (NULL == cr)
150   {
151     GNUNET_break (0);
152     return GNUNET_NO;
153   }
154   sj = GNUNET_new (struct TRANSPORT_TESTING_SendJob);
155   sj->num = num;
156   sj->sender = sender;
157   sj->receiver = receiver;
158   sj->cont = cont;
159   sj->cont_cls = cont_cls;
160   sj->mtype = mtype;
161   sj->msize = msize;
162   GNUNET_CONTAINER_DLL_insert (tth->sj_head,
163                                tth->sj_tail,
164                                sj);
165   {
166     char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
167
168     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
169                 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
170                 sender->no,
171                 GNUNET_i2s (&sender->id),
172                 receiver->no,
173                 receiver_s);
174     GNUNET_free (receiver_s);
175   }
176   sj->th = GNUNET_TRANSPORT_notify_transmit_ready (sender->th,
177                                                    &receiver->id,
178                                                    msize,
179                                                    TIMEOUT_TRANSMIT,
180                                                    &notify_ready,
181                                                    sj);
182   GNUNET_assert (NULL != sj->th);
183   return GNUNET_OK;
184 }
185
186
187 /**
188  * Task that sends a test message from the 
189  * first peer to the second peer.
190  *
191  * @param ccc context which should contain at least two peers, the
192  *        first two of which should be currently connected
193  * @param size desired message size
194  * @param cont continuation to call after transmission
195  * @param cont_cls closure for @a cont
196  */
197 static void
198 do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
199          uint16_t size,
200          GNUNET_SCHEDULER_TaskCallback cont,
201          void *cont_cls)
202 {
203   int ret;
204
205   ccc->global_ret = GNUNET_SYSERR;
206   ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
207                                        ccc->p[1],
208                                        GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
209                                        size,
210                                        ccc->send_num_gen++,
211                                        cont,
212                                        cont_cls);
213   GNUNET_assert (GNUNET_SYSERR != ret);
214   if (GNUNET_NO == ret)
215   {
216     GNUNET_break (0);
217     ccc->global_ret = GNUNET_SYSERR;
218     GNUNET_SCHEDULER_shutdown ();
219   }
220 }
221
222
223 /**
224  * Task that sends a minimalistic test message from the 
225  * first peer to the second peer.
226  *
227  * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
228  *        which should contain at least two peers, the first two
229  *        of which should be currently connected
230  */
231 void
232 GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
233 {
234   struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
235   int done;
236   size_t msize;
237
238   if (0 < sc->num_messages)
239   {
240     sc->num_messages--;
241     done = (0 == sc->num_messages);
242   }
243   else
244   {
245     done = 0; /* infinite loop */
246   }
247   msize = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage);
248   if (NULL != sc->get_size_cb)
249     msize = sc->get_size_cb (sc->num_messages);
250   /* if this was the last message, call the continuation,
251      otherwise call this function again */
252   do_send (sc->ccc,
253            msize,
254            done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
255            done ? sc->cont_cls : sc);
256 }
257
258
259 /**
260  * Task that sends a large test message from the 
261  * first peer to the second peer.
262  *
263  * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
264  *        which should contain at least two peers, the first two
265  *        of which should be currently connected
266  */
267 void
268 GNUNET_TRANSPORT_TESTING_large_send (void *cls)
269 {
270   struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
271   int done;
272   size_t msize;
273
274   if (0 < sc->num_messages)
275   {
276     sc->num_messages--;
277     done = (0 == sc->num_messages);
278   }
279   else
280   {
281     done = 0; /* infinite loop */
282   }
283   msize = 2600;
284   if (NULL != sc->get_size_cb)
285     msize = sc->get_size_cb (sc->num_messages);
286   /* if this was the last message, call the continuation,
287      otherwise call this function again */
288   do_send (sc->ccc,
289            msize,
290            done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
291            done ? sc->cont_cls : sc);
292 }
293
294 /* end of transport-testing-send.c */