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