25f1c2053f76d16f7da8a88ac5f11b6d9b642e17
[oweals/gnunet.git] / src / fragmentation / test_fragmentation.c
1 /*
2      This file is part of GNUnet
3      (C) 2004, 2009 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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 VERBOSE GNUNET_NO
29
30 #define DETAILS GNUNET_NO
31
32 /**
33  * Number of messages to transmit (note: each uses ~32k memory!)
34  */
35 #define NUM_MSGS 5000
36
37 /**
38  * MTU to force on fragmentation (must be > 1k + 12)
39  */
40 #define MTU 1111
41
42 /**
43  * Simulate dropping of 1 out of how many messages? (must be > 1)
44  */
45 #define DROPRATE 10
46
47 static int ret = 1; 
48
49 static unsigned int dups;
50
51 static unsigned int fragc;
52
53 static unsigned int frag_drops;
54
55 static unsigned int acks;
56
57 static unsigned int ack_drops;
58
59 static struct GNUNET_DEFRAGMENT_Context *defrag;
60
61 static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS];
62
63 static struct GNUNET_FRAGMENT_Context *frags[NUM_MSGS];
64
65 static void
66 proc_msgs (void *cls,
67            const struct GNUNET_MessageHeader *hdr)
68 {
69   static unsigned int total;
70   unsigned int i;
71   const char *buf;
72
73 #if DETAILS
74   fprintf (stderr, "!"); /* message complete, good! */
75 #endif
76   buf = (const char*) hdr;
77   for (i=sizeof (struct GNUNET_MessageHeader);i<ntohs(hdr->size);i++)
78     GNUNET_assert (buf[i] == (char) i);
79   total++;
80 #if ! DETAILS
81   if (0 == (total % (NUM_MSGS / 100)))
82     fprintf (stderr, ".");
83 #endif
84   /* tolerate 10% loss, i.e. due to duplicate fragment IDs */
85   if (total >= NUM_MSGS - (NUM_MSGS / 10))
86     {
87       ret = 0;
88       GNUNET_DEFRAGMENT_context_destroy (defrag);
89       defrag = NULL;
90       for (i=0;i<NUM_MSGS;i++)
91         {
92           if (frags[i] == NULL)
93             continue;
94           GNUNET_FRAGMENT_context_destroy (frags[i]);
95           frags[i] = NULL;
96         }
97     }
98 }
99
100
101 /**
102  * Process ACK (by passing to fragmenter)
103  */
104 static void
105 proc_acks (void *cls,
106            uint32_t msg_id,
107            const struct GNUNET_MessageHeader *hdr)
108 {
109   unsigned int i;
110   int ret;
111
112   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
113     {                                           
114       ack_drops++;
115       return; /* random drop */
116     }
117   for (i=0;i<NUM_MSGS;i++)
118     {
119       if (frags[i] == NULL)
120         continue;     
121       ret = GNUNET_FRAGMENT_process_ack (frags[i],
122                                          hdr);
123       if (ret == GNUNET_OK)
124         {
125 #if DETAILS
126           fprintf (stderr, "@"); /* good ACK */
127 #endif
128           GNUNET_FRAGMENT_context_destroy (frags[i]);
129           frags[i] = NULL;
130           acks++;
131           return;
132         }
133       if (ret == GNUNET_NO)
134         {
135 #if DETAILS
136           fprintf (stderr, "@"); /* good ACK */
137 #endif
138           acks++;
139           return;
140         }
141     }
142 #if DETAILS
143   fprintf (stderr, "_"); /* BAD: ack that nobody feels responsible for... */
144 #endif
145 }
146
147
148 /**
149  * Process fragment (by passing to defrag).
150  */
151 static void
152 proc_frac (void *cls,
153            const struct GNUNET_MessageHeader *hdr)
154 {
155   struct GNUNET_FRAGMENT_Context **fc = cls;
156   int ret;
157
158   GNUNET_FRAGMENT_context_transmission_done (*fc);
159   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
160     {
161       frag_drops++;
162       return; /* random drop */
163     }
164   if (NULL == defrag)
165     {
166       fprintf (stderr, "E"); /* Error: frag after shutdown!? */
167       return;
168     }
169   ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr);
170   if (ret == GNUNET_NO)
171     {
172 #if DETAILS
173       fprintf (stderr, "?"); /* duplicate fragment */
174 #endif
175       dups++;
176     }
177   else if (ret == GNUNET_OK)
178     {
179 #if DETAILS
180       fprintf (stderr, "."); /* good fragment */
181 #endif
182       fragc++;
183     }
184 }
185
186
187 /**
188  * Main function run with scheduler.
189  */
190 static void
191 run (void *cls,
192      char *const *args,
193      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
194 {
195   unsigned int i;
196   struct GNUNET_MessageHeader *msg;
197   char buf[MTU + 32 * 1024];
198
199   defrag = GNUNET_DEFRAGMENT_context_create (NULL,
200                                              MTU,
201                                              NUM_MSGS /* enough space for all */,
202                                              NULL,
203                                              &proc_msgs,
204                                              &proc_acks);
205   for (i=0;i<sizeof(buf);i++)
206     buf[i] = (char) i;
207   msg = (struct GNUNET_MessageHeader* ) buf;
208   for (i=0;i<NUM_MSGS;i++)
209     {
210       msg->type = htons ((uint16_t) i);
211       msg->size = htons (sizeof (struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024));
212       frags[i] = GNUNET_FRAGMENT_context_create (NULL /* no stats */, 
213                                                  MTU,
214                                                  &trackers[i],
215                                                  GNUNET_TIME_UNIT_SECONDS,
216                                                  msg,
217                                                  &proc_frac,
218                                                  &frags[i]);
219     }
220 }
221
222
223 int
224 main (int argc, char *argv[])
225 {
226   struct GNUNET_GETOPT_CommandLineOption options[] = {
227     GNUNET_GETOPT_OPTION_END
228   };
229   char *const argv_prog[] = {
230     "test-fragmentation",
231     "-c",
232     "test_fragmentation_data.conf",
233     "-L",
234 #if VERBOSE
235     "DEBUG",
236 #else
237     "WARNING",
238 #endif
239     NULL
240   };
241   unsigned int i;
242
243   GNUNET_log_setup ("test-fragmentation",
244 #if VERBOSE
245                     "DEBUG",
246 #else
247                     "WARNING",
248 #endif
249                     NULL);
250   for (i=0;i<NUM_MSGS;i++)
251     GNUNET_BANDWIDTH_tracker_init (&trackers[i],
252                                    GNUNET_BANDWIDTH_value_init ((i+1) * 1024),
253                                    100);
254   GNUNET_PROGRAM_run (5, argv_prog, "test-fragmentation", "nohelp", options, &run, NULL);
255   fprintf (stderr, 
256            "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n",
257            fragc,
258            dups,
259            acks,
260            ack_drops);
261   return ret;
262 }