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