revert
[oweals/gnunet.git] / src / fragmentation / test_fragmentation_parallel.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 500
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 5
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 *frags[NUM_MSGS];
60
61 static struct GNUNET_SCHEDULER_Task *shutdown_task;
62
63
64 static void
65 do_shutdown (void *cls)
66 {
67   unsigned int i;
68
69   ret = 0;
70   shutdown_task = NULL;
71   GNUNET_DEFRAGMENT_context_destroy (defrag);
72   defrag = NULL;
73   for (i = 0; i < NUM_MSGS; i++)
74   {
75     if (frags[i] == NULL)
76       continue;
77     GNUNET_FRAGMENT_context_destroy (frags[i], NULL, NULL);
78     frags[i] = NULL;
79   }
80 }
81
82
83 static void
84 proc_msgs (void *cls, const struct GNUNET_MessageHeader *hdr)
85 {
86   static unsigned int total;
87   unsigned int i;
88   const char *buf;
89
90 #if DETAILS
91   FPRINTF (stderr, "%s",  "!");        /* message complete, good! */
92 #endif
93   buf = (const char *) hdr;
94   for (i = sizeof (struct GNUNET_MessageHeader); i < ntohs (hdr->size); i++)
95     GNUNET_assert (buf[i] == (char) i);
96   total++;
97 #if ! DETAILS
98   if (0 == (total % (NUM_MSGS / 100)))
99     FPRINTF (stderr, "%s",  ".");
100 #endif
101   /* tolerate 10% loss, i.e. due to duplicate fragment IDs */
102   if ((total >= NUM_MSGS - (NUM_MSGS / 10)) && (ret != 0))
103   {
104     if (NULL == shutdown_task)
105       shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
106   }
107 }
108
109
110 /**
111  * Process ACK (by passing to fragmenter)
112  */
113 static void
114 proc_acks (void *cls, uint32_t msg_id, const struct GNUNET_MessageHeader *hdr)
115 {
116   unsigned int i;
117   int ret;
118
119   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
120   {
121     ack_drops++;
122     return;                     /* random drop */
123   }
124   for (i = 0; i < NUM_MSGS; i++)
125   {
126     if (frags[i] == NULL)
127       continue;
128     ret = GNUNET_FRAGMENT_process_ack (frags[i], hdr);
129     if (ret == GNUNET_OK)
130     {
131 #if DETAILS
132       FPRINTF (stderr, "%s",  "@");    /* good ACK */
133 #endif
134       GNUNET_FRAGMENT_context_destroy (frags[i], NULL, NULL);
135       frags[i] = NULL;
136       acks++;
137       return;
138     }
139     if (ret == GNUNET_NO)
140     {
141 #if DETAILS
142       FPRINTF (stderr, "%s",  "@");    /* good ACK */
143 #endif
144       acks++;
145       return;
146     }
147   }
148 #if DETAILS
149   FPRINTF (stderr, "%s",  "_");        /* BAD: ack that nobody feels responsible for... */
150 #endif
151 }
152
153
154 /**
155  * Process fragment (by passing to defrag).
156  */
157 static void
158 proc_frac (void *cls, const struct GNUNET_MessageHeader *hdr)
159 {
160   struct GNUNET_FRAGMENT_Context **fc = cls;
161   int ret;
162
163   GNUNET_FRAGMENT_context_transmission_done (*fc);
164   if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
165   {
166     frag_drops++;
167     return;                     /* random drop */
168   }
169   if (NULL == defrag)
170   {
171     FPRINTF (stderr, "%s",  "E");      /* Error: frag after shutdown!? */
172     return;
173   }
174   ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr);
175   if (ret == GNUNET_NO)
176   {
177 #if DETAILS
178     FPRINTF (stderr, "%s",  "?");      /* duplicate fragment */
179 #endif
180     dups++;
181   }
182   else if (ret == GNUNET_OK)
183   {
184 #if DETAILS
185     FPRINTF (stderr, "%s",  ".");      /* good fragment */
186 #endif
187     fragc++;
188   }
189 }
190
191
192 /**
193  * Main function run with scheduler.
194  */
195 static void
196 run (void *cls, char *const *args, const char *cfgfile,
197      const struct GNUNET_CONFIGURATION_Handle *cfg)
198 {
199   unsigned int i;
200   struct GNUNET_MessageHeader *msg;
201   char buf[MTU + 32 * 1024];
202
203   defrag = GNUNET_DEFRAGMENT_context_create (NULL, MTU, NUM_MSGS        /* enough space for all */
204                                              , NULL, &proc_msgs, &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 =
212         htons (sizeof (struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024));
213     frags[i] = GNUNET_FRAGMENT_context_create (NULL /* no stats */ ,
214                                                MTU, &trackers[i],
215                                                GNUNET_TIME_UNIT_MILLISECONDS,
216                                                GNUNET_TIME_UNIT_SECONDS,
217                                                msg,
218                                                &proc_frac, &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     "WARNING",
235     NULL
236   };
237   unsigned int i;
238
239   GNUNET_log_setup ("test-fragmentation",
240                     "WARNING",
241                     NULL);
242   for (i = 0; i < NUM_MSGS; i++)
243     GNUNET_BANDWIDTH_tracker_init (&trackers[i], NULL, NULL,
244                                    GNUNET_BANDWIDTH_value_init ((i + 1) * 1024),
245                                    100);
246   GNUNET_PROGRAM_run (5, argv_prog, "test-fragmentation", "nohelp", options,
247                       &run, NULL);
248   FPRINTF (stderr,
249            "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n",
250            fragc, dups, acks, ack_drops);
251   return ret;
252 }