60fed23a694ab1a362c1545b07be26e9e8fc4e96
[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   *cr = cx;
100 }
101
102
103 /**
104  * Send a test message of type @a mtype and size @a msize from
105  * peer @a sender to peer @a receiver.  The peers should be
106  * connected when this function is called.
107  *
108  * @param sender the sending peer
109  * @param receiver the receiving peer
110  * @param mtype message type to use
111  * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
112  * @param num unique message number
113  * @param cont continuation to call after transmission
114  * @param cont_cls closure for @a cont
115  * @return #GNUNET_OK if message was queued,
116  *         #GNUNET_NO if peers are not connected
117  *         #GNUNET_SYSERR if @a msize is illegal
118  */
119 int
120 GNUNET_TRANSPORT_TESTING_send (struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
121                                struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
122                                uint16_t mtype,
123                                uint16_t msize,
124                                uint32_t num,
125                                GNUNET_SCHEDULER_TaskCallback cont,
126                                void *cont_cls)
127 {
128   struct GNUNET_TRANSPORT_TESTING_Handle *tth = sender->tth;
129   struct TRANSPORT_TESTING_SendJob *sj;
130   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
131
132   if (msize < sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage))
133   {
134     GNUNET_break (0);
135     return GNUNET_SYSERR;
136   }
137   cr = NULL;
138   GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
139                                                     receiver,
140                                                     &find_cr,
141                                                     &cr);
142   if (NULL == cr)
143     GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
144                                                       sender,
145                                                       &find_cr,
146                                                       &cr);
147   if ( (NULL == cr) ||
148        (GNUNET_YES != cr->connected) )
149   {
150     GNUNET_break (0);
151     return GNUNET_NO;
152   }
153   sj = GNUNET_new (struct TRANSPORT_TESTING_SendJob);
154   sj->num = num;
155   sj->sender = sender;
156   sj->receiver = receiver;
157   sj->cont = cont;
158   sj->cont_cls = cont_cls;
159   sj->mtype = mtype;
160   sj->msize = msize;
161   GNUNET_CONTAINER_DLL_insert (tth->sj_head,
162                                tth->sj_tail,
163                                sj);
164   {
165     char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
166
167     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
168                 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
169                 sender->no,
170                 GNUNET_i2s (&sender->id),
171                 receiver->no,
172                 receiver_s);
173     GNUNET_free (receiver_s);
174   }
175   sj->th = GNUNET_TRANSPORT_notify_transmit_ready (sender->th,
176                                                    &receiver->id,
177                                                    msize,
178                                                    TIMEOUT_TRANSMIT,
179                                                    &notify_ready,
180                                                    sj);
181   GNUNET_assert (NULL != sj->th);
182   return GNUNET_OK;
183 }
184
185
186 /**
187  * Task that sends a test message from the 
188  * first peer to the second peer.
189  *
190  * @param ccc context which should contain at least two peers, the
191  *        first two of which should be currently connected
192  * @param size desired message size
193  * @param cont continuation to call after transmission
194  * @param cont_cls closure for @a cont
195  */
196 static void
197 do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
198          uint16_t size,
199          GNUNET_SCHEDULER_TaskCallback cont,
200          void *cont_cls)
201 {
202   int ret;
203
204   ccc->global_ret = GNUNET_SYSERR;
205   ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
206                                        ccc->p[1],
207                                        GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
208                                        size,
209                                        ccc->send_num_gen++,
210                                        cont,
211                                        cont_cls);
212   GNUNET_assert (GNUNET_SYSERR != ret);
213   if (GNUNET_NO == ret)
214   {
215     GNUNET_break (0);
216     ccc->global_ret = GNUNET_SYSERR;
217     GNUNET_SCHEDULER_shutdown ();
218   }
219 }
220
221
222 /**
223  * Task that sends a minimalistic test message from the 
224  * first peer to the second peer.
225  *
226  * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
227  *        which should contain at least two peers, the first two
228  *        of which should be currently connected
229  */
230 void
231 GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
232 {
233   struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
234   int done;
235   size_t msize;
236
237   if (0 < sc->num_messages)
238   {
239     sc->num_messages--;
240     done = (0 == sc->num_messages);
241   }
242   else
243   {
244     done = 0; /* infinite loop */
245   }
246   msize = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage);
247   if (NULL != sc->get_size_cb)
248     msize = sc->get_size_cb (sc->num_messages);
249   /* if this was the last message, call the continuation,
250      otherwise call this function again */
251   do_send (sc->ccc,
252            msize,
253            done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
254            done ? sc->cont_cls : sc);
255 }
256
257
258 /**
259  * Task that sends a large test message from the 
260  * first peer to the second peer.
261  *
262  * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
263  *        which should contain at least two peers, the first two
264  *        of which should be currently connected
265  */
266 void
267 GNUNET_TRANSPORT_TESTING_large_send (void *cls)
268 {
269   struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
270   int done;
271   size_t msize;
272
273   if (0 < sc->num_messages)
274   {
275     sc->num_messages--;
276     done = (0 == sc->num_messages);
277   }
278   else
279   {
280     done = 0; /* infinite loop */
281   }
282   msize = 2600;
283   if (NULL != sc->get_size_cb)
284     msize = sc->get_size_cb (sc->num_messages);
285   /* if this was the last message, call the continuation,
286      otherwise call this function again */
287   do_send (sc->ccc,
288            msize,
289            done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
290            done ? sc->cont_cls : sc);
291 }
292
293 /* end of transport-testing-send.c */