paragraph for gnunet devs that don't know how to use the web
[oweals/gnunet.git] / src / fragmentation / test_fragmentation.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2004, 2009 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19  * @file fragmentation/test_fragmentation.c
20  * @brief test for fragmentation.c
21  * @author Christian Grothoff
22  */
23 #include "platform.h"
24 #include "gnunet_fragmentation_lib.h"
25
26 #define DETAILS GNUNET_NO
27
28 /**
29  * Number of messages to transmit (note: each uses ~32k memory!)
30  */
31 #define NUM_MSGS 1000
32
33 /**
34  * MTU to force on fragmentation (must be > 1k + 12)
35  */
36 #define MTU 1111
37
38 /**
39  * Simulate dropping of 1 out of how many messages? (must be > 1)
40  */
41 #define DROPRATE 15
42
43 static int ret = 1;
44
45 static unsigned int dups;
46
47 static unsigned int fragc;
48
49 static unsigned int frag_drops;
50
51 static unsigned int acks;
52
53 static unsigned int ack_drops;
54
55 static struct GNUNET_DEFRAGMENT_Context *defrag;
56
57 static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS];
58
59 static struct GNUNET_FRAGMENT_Context *frag;
60
61 static struct GNUNET_SCHEDULER_Task * shutdown_task;
62
63 static struct GNUNET_TIME_Relative msg_delay;
64
65 static struct GNUNET_TIME_Relative ack_delay;
66
67
68 static void
69 do_shutdown (void *cls)
70 {
71   ret = 0;
72   shutdown_task = NULL;
73   GNUNET_DEFRAGMENT_context_destroy (defrag);
74   defrag = NULL;
75   if (NULL != frag)
76   {
77     GNUNET_FRAGMENT_context_destroy (frag, &msg_delay, &ack_delay);
78     frag = NULL;
79   }
80   fprintf (stderr,
81            "\nFinal message-delay: %s\n",
82            GNUNET_STRINGS_relative_time_to_string (msg_delay,
83                                                    GNUNET_YES));
84   fprintf (stderr,
85            "Final ack-delay: %s\n",
86            GNUNET_STRINGS_relative_time_to_string (ack_delay,
87                                                    GNUNET_YES));
88 }
89
90
91 static void
92 proc_msgs (void *cls, const struct GNUNET_MessageHeader *hdr)
93 {
94   static unsigned int total;
95   unsigned int i;
96   const char *buf;
97
98 #if DETAILS
99   FPRINTF (stderr, "%s",  "M! ");        /* message complete, good! */
100 #endif
101   buf = (const char *) hdr;
102   for (i = sizeof (struct GNUNET_MessageHeader); i < ntohs (hdr->size); i++)
103     GNUNET_assert (buf[i] == (char) i);
104   total++;
105 #if ! DETAILS
106   if (0 == (total % (NUM_MSGS / 100)))
107     FPRINTF (stderr, "%s",  ".");
108 #endif
109   /* tolerate 10% loss, i.e. due to duplicate fragment IDs */
110   if ((total >= NUM_MSGS - (NUM_MSGS / 10)) && (ret != 0))
111   {
112     if (NULL == shutdown_task)
113       shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
114   }
115 }
116
117
118 /**
119  * Process fragment (by passing to defrag).
120  */
121 static void
122 proc_frac (void *cls, const struct GNUNET_MessageHeader *hdr)
123 {
124   struct GNUNET_FRAGMENT_Context **fc = cls;
125   int ret;
126
127   GNUNET_FRAGMENT_context_transmission_done (*fc);
128   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
129   {
130     frag_drops++;
131 #if DETAILS
132     FPRINTF (stderr, "%s",  "DF ");    /* dropped Frag */
133 #endif
134     return;                     /* random drop */
135   }
136   if (NULL == defrag)
137   {
138     FPRINTF (stderr, "%s",  "?E ");      /* Error: frag after shutdown!? */
139     return;
140   }
141   ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr);
142   if (ret == GNUNET_NO)
143   {
144 #if DETAILS
145     FPRINTF (stderr, "%s",  "FF ");      /* duplicate fragment */
146 #endif
147     dups++;
148   }
149   else if (ret == GNUNET_OK)
150   {
151 #if DETAILS
152     FPRINTF (stderr, "%s",  "F! ");      /* good fragment */
153 #endif
154     fragc++;
155   }
156 }
157
158
159 static void
160 next_transmission ()
161 {
162   static unsigned int i;
163   struct GNUNET_MessageHeader *msg;
164   static char buf[MTU + 32 * 1024];
165   unsigned int j;
166
167   if (0 == i)
168   {
169     for (j = 0; j < sizeof (buf); j++)
170       buf[j] = (char) j;
171   }
172   else
173   {
174     GNUNET_FRAGMENT_context_destroy (frag,
175                                      &msg_delay,
176                                      &ack_delay);
177     frag = NULL;
178   }
179   if (i == NUM_MSGS)
180     return;
181 #if DETAILS
182   FPRINTF (stderr, "%s",  "T! ");        /* sending message */
183 #endif
184   msg = (struct GNUNET_MessageHeader *) buf;
185   msg->type = htons ((uint16_t) i);
186   msg->size =
187     htons (sizeof (struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024));
188   frag = GNUNET_FRAGMENT_context_create (NULL /* no stats */ ,
189                                          MTU, &trackers[i],
190                                          msg_delay,
191                                          ack_delay,
192                                          msg,
193                                          &proc_frac, &frag);
194   i++;
195 }
196
197
198 /**
199  * Process ACK (by passing to fragmenter)
200  */
201 static void
202 proc_acks (void *cls,
203            uint32_t msg_id,
204            const struct GNUNET_MessageHeader *hdr)
205 {
206   unsigned int i;
207   int ret;
208
209   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
210   {
211     ack_drops++;
212 #if DETAILS
213     FPRINTF (stderr, "%s",  "DA ");    /* dropped ACK */
214 #endif
215     return;                     /* random drop */
216   }
217   for (i = 0; i < NUM_MSGS; i++)
218   {
219     if (NULL == frag)
220       continue;
221     ret = GNUNET_FRAGMENT_process_ack (frag, hdr);
222     if (ret == GNUNET_OK)
223     {
224 #if DETAILS
225       FPRINTF (stderr, "%s",  "GA ");    /* good ACK */
226 #endif
227       next_transmission ();
228       acks++;
229       return;
230     }
231     if (ret == GNUNET_NO)
232     {
233 #if DETAILS
234       FPRINTF (stderr, "%s",  "AA ");    /* duplciate ACK */
235 #endif
236       acks++;
237       return;
238     }
239   }
240 #if DETAILS
241   FPRINTF (stderr, "%s",  "?A ");        /* BAD: ack that nobody feels responsible for... */
242 #endif
243 }
244
245
246 /**
247  * Main function run with scheduler.
248  */
249 static void
250 run (void *cls,
251      char *const *args,
252      const char *cfgfile,
253      const struct GNUNET_CONFIGURATION_Handle *cfg)
254 {
255   defrag = GNUNET_DEFRAGMENT_context_create (NULL, MTU,
256                                              3,
257                                              NULL,
258                                              &proc_msgs,
259                                              &proc_acks);
260   next_transmission ();
261 }
262
263
264 int
265 main (int argc, char *argv[])
266 {
267   struct GNUNET_GETOPT_CommandLineOption options[] = {
268     GNUNET_GETOPT_OPTION_END
269   };
270   char *const argv_prog[] = {
271     "test-fragmentation",
272     "-c",
273     "test_fragmentation_data.conf",
274     "-L",
275     "WARNING",
276     NULL
277   };
278   unsigned int i;
279
280   msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
281   ack_delay = GNUNET_TIME_UNIT_SECONDS;
282   GNUNET_log_setup ("test-fragmentation",
283                     "WARNING",
284                     NULL);
285   for (i = 0; i < NUM_MSGS; i++)
286     GNUNET_BANDWIDTH_tracker_init (&trackers[i], NULL, NULL,
287                                    GNUNET_BANDWIDTH_value_init ((i + 1) * 1024),
288                                    100);
289   GNUNET_PROGRAM_run (5,
290                       argv_prog,
291                       "test-fragmentation", "nohelp",
292                       options,
293                       &run, NULL);
294   FPRINTF (stderr,
295            "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n",
296            fragc,
297            dups,
298            acks,
299            ack_drops);
300   return ret;
301 }