aboutsummaryrefslogtreecommitdiff
path: root/src/fragmentation
diff options
context:
space:
mode:
Diffstat (limited to 'src/fragmentation')
-rw-r--r--src/fragmentation/.gitignore2
-rw-r--r--src/fragmentation/Makefile.am42
-rw-r--r--src/fragmentation/defragmentation.c590
-rw-r--r--src/fragmentation/fragmentation.c528
-rw-r--r--src/fragmentation/fragmentation.h85
-rw-r--r--src/fragmentation/test_fragmentation.c303
-rw-r--r--src/fragmentation/test_fragmentation_data.conf5
-rw-r--r--src/fragmentation/test_fragmentation_parallel.c254
8 files changed, 0 insertions, 1809 deletions
diff --git a/src/fragmentation/.gitignore b/src/fragmentation/.gitignore
deleted file mode 100644
index c3293ab69..000000000
--- a/src/fragmentation/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
1test_fragmentation
2test_fragmentation_parallel
diff --git a/src/fragmentation/Makefile.am b/src/fragmentation/Makefile.am
deleted file mode 100644
index 85df01ff5..000000000
--- a/src/fragmentation/Makefile.am
+++ /dev/null
@@ -1,42 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage
6endif
7
8lib_LTLIBRARIES = libgnunetfragmentation.la
9
10libgnunetfragmentation_la_SOURCES = \
11 fragmentation.c fragmentation.h \
12 defragmentation.c
13libgnunetfragmentation_la_LIBADD = -lm \
14 $(top_builddir)/src/statistics/libgnunetstatistics.la \
15 $(top_builddir)/src/util/libgnunetutil.la \
16 $(LTLIBINTL)
17libgnunetfragmentation_la_LDFLAGS = \
18 $(GN_LIB_LDFLAGS) \
19 -version-info 2:0:0
20
21check_PROGRAMS = \
22 test_fragmentation \
23 test_fragmentation_parallel
24
25if ENABLE_TEST_RUN
26AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
27TESTS = $(check_PROGRAMS)
28endif
29
30test_fragmentation_SOURCES = \
31 test_fragmentation.c
32test_fragmentation_LDADD = \
33 libgnunetfragmentation.la \
34 $(top_builddir)/src/util/libgnunetutil.la
35
36test_fragmentation_parallel_SOURCES = \
37 test_fragmentation_parallel.c
38test_fragmentation_parallel_LDADD = \
39 libgnunetfragmentation.la \
40 $(top_builddir)/src/util/libgnunetutil.la
41
42EXTRA_DIST = test_fragmentation_data.conf
diff --git a/src/fragmentation/defragmentation.c b/src/fragmentation/defragmentation.c
deleted file mode 100644
index c0ca86b37..000000000
--- a/src/fragmentation/defragmentation.c
+++ /dev/null
@@ -1,590 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2011 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/fragmentation/defragmentation.c
22 * @brief library to help defragment messages
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_fragmentation_lib.h"
27#include "fragmentation.h"
28
29/**
30 * Timestamps for fragments.
31 */
32struct FragTimes
33{
34 /**
35 * The time the fragment was received.
36 */
37 struct GNUNET_TIME_Absolute time;
38
39 /**
40 * Number of the bit for the fragment (in [0,..,63]).
41 */
42 unsigned int bit;
43};
44
45
46/**
47 * Information we keep for one message that is being assembled. Note
48 * that we keep the context around even after the assembly is done to
49 * handle 'stray' messages that are received 'late'. A message
50 * context is ONLY discarded when the queue gets too big.
51 */
52struct MessageContext
53{
54 /**
55 * This is a DLL.
56 */
57 struct MessageContext *next;
58
59 /**
60 * This is a DLL.
61 */
62 struct MessageContext *prev;
63
64 /**
65 * Associated defragmentation context.
66 */
67 struct GNUNET_DEFRAGMENT_Context *dc;
68
69 /**
70 * Pointer to the assembled message, allocated at the
71 * end of this struct.
72 */
73 const struct GNUNET_MessageHeader *msg;
74
75 /**
76 * Last time we received any update for this message
77 * (least-recently updated message will be discarded
78 * if we hit the queue size).
79 */
80 struct GNUNET_TIME_Absolute last_update;
81
82 /**
83 * Task scheduled for transmitting the next ACK to the
84 * other peer.
85 */
86 struct GNUNET_SCHEDULER_Task *ack_task;
87
88 /**
89 * When did we receive which fragment? Used to calculate
90 * the time we should send the ACK.
91 */
92 struct FragTimes frag_times[64];
93
94 /**
95 * Which fragments have we gotten yet? bits that are 1
96 * indicate missing fragments.
97 */
98 uint64_t bits;
99
100 /**
101 * Unique ID for this message.
102 */
103 uint32_t fragment_id;
104
105 /**
106 * Which 'bit' did the last fragment we received correspond to?
107 */
108 unsigned int last_bit;
109
110 /**
111 * For the current ACK round, which is the first relevant
112 * offset in @e frag_times?
113 */
114 unsigned int frag_times_start_offset;
115
116 /**
117 * Which offset would we write the next frag value into
118 * in the @e frag_times array? All smaller entries are valid.
119 */
120 unsigned int frag_times_write_offset;
121
122 /**
123 * Total size of the message that we are assembling.
124 */
125 uint16_t total_size;
126
127 /**
128 * Was the last fragment we got a duplicate?
129 */
130 int16_t last_duplicate;
131};
132
133
134/**
135 * Defragmentation context (one per connection).
136 */
137struct GNUNET_DEFRAGMENT_Context
138{
139 /**
140 * For statistics.
141 */
142 struct GNUNET_STATISTICS_Handle *stats;
143
144 /**
145 * Head of list of messages we're defragmenting.
146 */
147 struct MessageContext *head;
148
149 /**
150 * Tail of list of messages we're defragmenting.
151 */
152 struct MessageContext *tail;
153
154 /**
155 * Closure for @e proc and @e ackp.
156 */
157 void *cls;
158
159 /**
160 * Function to call with defragmented messages.
161 */
162 GNUNET_FRAGMENT_MessageProcessor proc;
163
164 /**
165 * Function to call with acknowledgements.
166 */
167 GNUNET_DEFRAGMENT_AckProcessor ackp;
168
169 /**
170 * Running average of the latency (delay between messages) for this
171 * connection.
172 */
173 struct GNUNET_TIME_Relative latency;
174
175 /**
176 * num_msgs how many fragmented messages
177 * to we defragment at most at the same time?
178 */
179 unsigned int num_msgs;
180
181 /**
182 * Current number of messages in the 'struct MessageContext'
183 * DLL (smaller or equal to 'num_msgs').
184 */
185 unsigned int list_size;
186
187 /**
188 * Maximum message size for each fragment.
189 */
190 uint16_t mtu;
191};
192
193
194/**
195 * Create a defragmentation context.
196 *
197 * @param stats statistics context
198 * @param mtu the maximum message size for each fragment
199 * @param num_msgs how many fragmented messages
200 * to we defragment at most at the same time?
201 * @param cls closure for @a proc and @a ackp
202 * @param proc function to call with defragmented messages
203 * @param ackp function to call with acknowledgements (to send
204 * back to the other side)
205 * @return the defragmentation context
206 */
207struct GNUNET_DEFRAGMENT_Context *
208GNUNET_DEFRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats,
209 uint16_t mtu, unsigned int num_msgs,
210 void *cls,
211 GNUNET_FRAGMENT_MessageProcessor proc,
212 GNUNET_DEFRAGMENT_AckProcessor ackp)
213{
214 struct GNUNET_DEFRAGMENT_Context *dc;
215
216 dc = GNUNET_new (struct GNUNET_DEFRAGMENT_Context);
217 dc->stats = stats;
218 dc->cls = cls;
219 dc->proc = proc;
220 dc->ackp = ackp;
221 dc->num_msgs = num_msgs;
222 dc->mtu = mtu;
223 dc->latency = GNUNET_TIME_UNIT_SECONDS; /* start with likely overestimate */
224 return dc;
225}
226
227
228/**
229 * Destroy the given defragmentation context.
230 *
231 * @param dc defragmentation context
232 */
233void
234GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc)
235{
236 struct MessageContext *mc;
237
238 while (NULL != (mc = dc->head))
239 {
240 GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, mc);
241 dc->list_size--;
242 if (NULL != mc->ack_task)
243 {
244 GNUNET_SCHEDULER_cancel (mc->ack_task);
245 mc->ack_task = NULL;
246 }
247 GNUNET_free (mc);
248 }
249 GNUNET_assert (0 == dc->list_size);
250 GNUNET_free (dc);
251}
252
253
254/**
255 * Send acknowledgement to the other peer now.
256 *
257 * @param cls the message context
258 */
259static void
260send_ack (void *cls)
261{
262 struct MessageContext *mc = cls;
263 struct GNUNET_DEFRAGMENT_Context *dc = mc->dc;
264 struct FragmentAcknowledgement fa;
265
266 mc->ack_task = NULL;
267 fa.header.size = htons (sizeof(struct FragmentAcknowledgement));
268 fa.header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT_ACK);
269 fa.fragment_id = htonl (mc->fragment_id);
270 fa.bits = GNUNET_htonll (mc->bits);
271 GNUNET_STATISTICS_update (mc->dc->stats,
272 _ ("# acknowledgements sent for fragment"),
273 1,
274 GNUNET_NO);
275 mc->last_duplicate = GNUNET_NO; /* clear flag */
276 dc->ackp (dc->cls,
277 mc->fragment_id,
278 &fa.header);
279}
280
281
282/**
283 * This function is from the GNU Scientific Library, linear/fit.c,
284 * Copyright (C) 2000 Brian Gough
285 */
286static void
287gsl_fit_mul (const double *x, const size_t xstride, const double *y,
288 const size_t ystride, const size_t n, double *c1, double *cov_11,
289 double *sumsq)
290{
291 double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0;
292
293 size_t i;
294
295 for (i = 0; i < n; i++)
296 {
297 m_x += (x[i * xstride] - m_x) / (i + 1.0);
298 m_y += (y[i * ystride] - m_y) / (i + 1.0);
299 }
300
301 for (i = 0; i < n; i++)
302 {
303 const double dx = x[i * xstride] - m_x;
304 const double dy = y[i * ystride] - m_y;
305
306 m_dx2 += (dx * dx - m_dx2) / (i + 1.0);
307 m_dxdy += (dx * dy - m_dxdy) / (i + 1.0);
308 }
309
310 /* In terms of y = b x */
311
312 {
313 double s2 = 0, d2 = 0;
314 double b = (m_x * m_y + m_dxdy) / (m_x * m_x + m_dx2);
315
316 *c1 = b;
317
318 /* Compute chi^2 = \sum (y_i - b * x_i)^2 */
319
320 for (i = 0; i < n; i++)
321 {
322 const double dx = x[i * xstride] - m_x;
323 const double dy = y[i * ystride] - m_y;
324 const double d = (m_y - b * m_x) + dy - b * dx;
325
326 d2 += d * d;
327 }
328
329 s2 = d2 / (n - 1.0); /* chisq per degree of freedom */
330
331 *cov_11 = s2 * 1.0 / (n * (m_x * m_x + m_dx2));
332
333 *sumsq = d2;
334 }
335}
336
337
338/**
339 * Estimate the latency between messages based on the most recent
340 * message time stamps.
341 *
342 * @param mc context with time stamps
343 * @return average delay between time stamps (based on least-squares fit)
344 */
345static struct GNUNET_TIME_Relative
346estimate_latency (struct MessageContext *mc)
347{
348 struct FragTimes *first;
349 size_t total = mc->frag_times_write_offset - mc->frag_times_start_offset;
350 double x[total];
351 double y[total];
352 size_t i;
353 double c1;
354 double cov11;
355 double sumsq;
356 struct GNUNET_TIME_Relative ret;
357
358 first = &mc->frag_times[mc->frag_times_start_offset];
359 GNUNET_assert (total > 1);
360 for (i = 0; i < total; i++)
361 {
362 x[i] = (double) i;
363 y[i] = (double) (first[i].time.abs_value_us - first[0].time.abs_value_us);
364 }
365 gsl_fit_mul (x, 1, y, 1, total, &c1, &cov11, &sumsq);
366 c1 += sqrt (sumsq); /* add 1 std dev */
367 ret.rel_value_us = (uint64_t) c1;
368 if (0 == ret.rel_value_us)
369 ret = GNUNET_TIME_UNIT_MICROSECONDS; /* always at least 1 */
370 return ret;
371}
372
373
374/**
375 * Discard the message context that was inactive for the longest time.
376 *
377 * @param dc defragmentation context
378 */
379static void
380discard_oldest_mc (struct GNUNET_DEFRAGMENT_Context *dc)
381{
382 struct MessageContext *old;
383 struct MessageContext *pos;
384
385 old = NULL;
386 pos = dc->head;
387 while (NULL != pos)
388 {
389 if ((old == NULL) ||
390 (old->last_update.abs_value_us > pos->last_update.abs_value_us))
391 old = pos;
392 pos = pos->next;
393 }
394 GNUNET_assert (NULL != old);
395 GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, old);
396 dc->list_size--;
397 if (NULL != old->ack_task)
398 {
399 GNUNET_SCHEDULER_cancel (old->ack_task);
400 old->ack_task = NULL;
401 }
402 GNUNET_free (old);
403}
404
405
406/**
407 * We have received a fragment. Process it.
408 *
409 * @param dc the context
410 * @param msg the message that was received
411 * @return #GNUNET_OK on success,
412 * #GNUNET_NO if this was a duplicate,
413 * #GNUNET_SYSERR on error
414 */
415int
416GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc,
417 const struct GNUNET_MessageHeader *msg)
418{
419 struct MessageContext *mc;
420 const struct FragmentHeader *fh;
421 uint16_t msize;
422 uint16_t foff;
423 uint32_t fid;
424 char *mbuf;
425 unsigned int bit;
426 struct GNUNET_TIME_Absolute now;
427 struct GNUNET_TIME_Relative delay;
428 unsigned int bc;
429 unsigned int b;
430 unsigned int n;
431 unsigned int num_fragments;
432 int duplicate;
433 int last;
434
435 if (ntohs (msg->size) < sizeof(struct FragmentHeader))
436 {
437 GNUNET_break_op (0);
438 return GNUNET_SYSERR;
439 }
440 if (ntohs (msg->size) > dc->mtu)
441 {
442 GNUNET_break_op (0);
443 return GNUNET_SYSERR;
444 }
445 fh = (const struct FragmentHeader *) msg;
446 msize = ntohs (fh->total_size);
447 if (msize < sizeof(struct GNUNET_MessageHeader))
448 {
449 GNUNET_break_op (0);
450 return GNUNET_SYSERR;
451 }
452 fid = ntohl (fh->fragment_id);
453 foff = ntohs (fh->offset);
454 if (foff >= msize)
455 {
456 GNUNET_break_op (0);
457 return GNUNET_SYSERR;
458 }
459 if (0 != (foff % (dc->mtu - sizeof(struct FragmentHeader))))
460 {
461 GNUNET_break_op (0);
462 return GNUNET_SYSERR;
463 }
464 GNUNET_STATISTICS_update (dc->stats,
465 _ ("# fragments received"),
466 1,
467 GNUNET_NO);
468 num_fragments = (ntohs (msg->size) + dc->mtu - sizeof(struct FragmentHeader)
469 - 1) / (dc->mtu - sizeof(struct FragmentHeader));
470 last = 0;
471 for (mc = dc->head; NULL != mc; mc = mc->next)
472 if (mc->fragment_id > fid)
473 last++;
474
475 mc = dc->head;
476 while ((NULL != mc) && (fid != mc->fragment_id))
477 mc = mc->next;
478 bit = foff / (dc->mtu - sizeof(struct FragmentHeader));
479 if (bit * (dc->mtu - sizeof(struct FragmentHeader)) + ntohs (msg->size)
480 - sizeof(struct FragmentHeader) > msize)
481 {
482 /* payload extends past total message size */
483 GNUNET_break_op (0);
484 return GNUNET_SYSERR;
485 }
486 if ((NULL != mc) && (msize != mc->total_size))
487 {
488 /* inconsistent message size */
489 GNUNET_break_op (0);
490 return GNUNET_SYSERR;
491 }
492 now = GNUNET_TIME_absolute_get ();
493 if (NULL == mc)
494 {
495 mc = GNUNET_malloc (sizeof(struct MessageContext) + msize);
496 mc->msg = (const struct GNUNET_MessageHeader *) &mc[1];
497 mc->dc = dc;
498 mc->total_size = msize;
499 mc->fragment_id = fid;
500 mc->last_update = now;
501 n = (msize + dc->mtu - sizeof(struct FragmentHeader) - 1) / (dc->mtu
502 - sizeof(struct
503 FragmentHeader));
504 if (n == 64)
505 mc->bits = UINT64_MAX; /* set all 64 bit */
506 else
507 mc->bits = (1LLU << n) - 1; /* set lowest 'bits' bit */
508 if (dc->list_size >= dc->num_msgs)
509 discard_oldest_mc (dc);
510 GNUNET_CONTAINER_DLL_insert (dc->head,
511 dc->tail,
512 mc);
513 dc->list_size++;
514 }
515
516 /* copy data to 'mc' */
517 if (0 != (mc->bits & (1LLU << bit)))
518 {
519 mc->bits -= 1LLU << bit;
520 mbuf = (char *) &mc[1];
521 GNUNET_memcpy (&mbuf[bit * (dc->mtu - sizeof(struct FragmentHeader))],
522 &fh[1],
523 ntohs (msg->size) - sizeof(struct FragmentHeader));
524 mc->last_update = now;
525 if (bit < mc->last_bit)
526 mc->frag_times_start_offset = mc->frag_times_write_offset;
527 mc->last_bit = bit;
528 mc->frag_times[mc->frag_times_write_offset].time = now;
529 mc->frag_times[mc->frag_times_write_offset].bit = bit;
530 mc->frag_times_write_offset++;
531 duplicate = GNUNET_NO;
532 }
533 else
534 {
535 duplicate = GNUNET_YES;
536 GNUNET_STATISTICS_update (dc->stats,
537 _ ("# duplicate fragments received"),
538 1,
539 GNUNET_NO);
540 }
541
542 /* count number of missing fragments after the current one */
543 bc = 0;
544 for (b = bit; b < 64; b++)
545 if (0 != (mc->bits & (1LLU << b)))
546 bc++;
547 else
548 bc = 0;
549
550 /* notify about complete message */
551 if ((GNUNET_NO == duplicate) &&
552 (0 == mc->bits))
553 {
554 GNUNET_STATISTICS_update (dc->stats,
555 _ ("# messages defragmented"),
556 1,
557 GNUNET_NO);
558 /* message complete, notify! */
559 dc->proc (dc->cls, mc->msg);
560 }
561 /* send ACK */
562 if (mc->frag_times_write_offset - mc->frag_times_start_offset > 1)
563 {
564 dc->latency = estimate_latency (mc);
565 }
566 delay = GNUNET_TIME_relative_saturating_multiply (dc->latency,
567 bc + 1);
568 if ((last + fid == num_fragments) ||
569 (0 == mc->bits) ||
570 (GNUNET_YES == duplicate))
571 {
572 /* message complete or duplicate or last missing fragment in
573 linear sequence; ACK now! */
574 delay = GNUNET_TIME_UNIT_ZERO;
575 }
576 if (NULL != mc->ack_task)
577 GNUNET_SCHEDULER_cancel (mc->ack_task);
578 mc->ack_task = GNUNET_SCHEDULER_add_delayed (delay,
579 &send_ack,
580 mc);
581 if (GNUNET_YES == duplicate)
582 {
583 mc->last_duplicate = GNUNET_YES;
584 return GNUNET_NO;
585 }
586 return GNUNET_YES;
587}
588
589
590/* end of defragmentation.c */
diff --git a/src/fragmentation/fragmentation.c b/src/fragmentation/fragmentation.c
deleted file mode 100644
index a2e097b8b..000000000
--- a/src/fragmentation/fragmentation.c
+++ /dev/null
@@ -1,528 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009-2013 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/fragmentation/fragmentation.c
22 * @brief library to help fragment messages
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_fragmentation_lib.h"
27#include "gnunet_protocols.h"
28#include "fragmentation.h"
29
30
31/**
32 * Absolute minimum delay we impose between sending and expecting ACK to arrive.
33 */
34#define MIN_ACK_DELAY GNUNET_TIME_relative_multiply ( \
35 GNUNET_TIME_UNIT_MILLISECONDS, 1)
36
37
38/**
39 * Fragmentation context.
40 */
41struct GNUNET_FRAGMENT_Context
42{
43 /**
44 * Statistics to use.
45 */
46 struct GNUNET_STATISTICS_Handle *stats;
47
48 /**
49 * Tracker for flow control.
50 */
51 struct GNUNET_BANDWIDTH_Tracker *tracker;
52
53 /**
54 * Current expected delay for ACKs.
55 */
56 struct GNUNET_TIME_Relative ack_delay;
57
58 /**
59 * Current expected delay between messages.
60 */
61 struct GNUNET_TIME_Relative msg_delay;
62
63 /**
64 * Next allowed transmission time.
65 */
66 struct GNUNET_TIME_Absolute delay_until;
67
68 /**
69 * Time we transmitted the last message of the last round.
70 */
71 struct GNUNET_TIME_Absolute last_round;
72
73 /**
74 * Message to fragment (allocated at the end of this struct).
75 */
76 const struct GNUNET_MessageHeader *msg;
77
78 /**
79 * Function to call for transmissions.
80 */
81 GNUNET_FRAGMENT_MessageProcessor proc;
82
83 /**
84 * Closure for @e proc.
85 */
86 void *proc_cls;
87
88 /**
89 * Bitfield, set to 1 for each unacknowledged fragment.
90 */
91 uint64_t acks;
92
93 /**
94 * Bitfield with all possible bits for @e acks (used to mask the
95 * ack we get back).
96 */
97 uint64_t acks_mask;
98
99 /**
100 * Task performing work for the fragmenter.
101 */
102 struct GNUNET_SCHEDULER_Task *task;
103
104 /**
105 * Our fragmentation ID. (chosen at random)
106 */
107 uint32_t fragment_id;
108
109 /**
110 * Round-robin selector for the next transmission.
111 */
112 unsigned int next_transmission;
113
114 /**
115 * How many rounds of transmission have we completed so far?
116 */
117 unsigned int num_rounds;
118
119 /**
120 * How many transmission have we completed in this round?
121 */
122 unsigned int num_transmissions;
123
124 /**
125 * #GNUNET_YES if we called @e proc and are now waiting for #GNUNET_FRAGMENT_context_transmission_done()
126 */
127 int8_t proc_busy;
128
129 /**
130 * #GNUNET_YES if we are waiting for an ACK.
131 */
132 int8_t wack;
133
134 /**
135 * Target fragment size.
136 */
137 uint16_t mtu;
138};
139
140
141/**
142 * Convert an ACK message to a printable format suitable for logging.
143 *
144 * @param ack message to print
145 * @return ack in human-readable format
146 */
147const char *
148GNUNET_FRAGMENT_print_ack (const struct GNUNET_MessageHeader *ack)
149{
150 static char buf[128];
151 const struct FragmentAcknowledgement *fa;
152
153 if (sizeof(struct FragmentAcknowledgement) !=
154 htons (ack->size))
155 return "<malformed ack>";
156 fa = (const struct FragmentAcknowledgement *) ack;
157 GNUNET_snprintf (buf,
158 sizeof(buf),
159 "%u-%llX",
160 ntohl (fa->fragment_id),
161 (unsigned long long) GNUNET_ntohll (fa->bits));
162 return buf;
163}
164
165
166/**
167 * Transmit the next fragment to the other peer.
168 *
169 * @param cls the `struct GNUNET_FRAGMENT_Context`
170 */
171static void
172transmit_next (void *cls)
173{
174 struct GNUNET_FRAGMENT_Context *fc = cls;
175 char msg[fc->mtu];
176 const char *mbuf;
177 struct FragmentHeader *fh;
178 struct GNUNET_TIME_Relative delay;
179 unsigned int bit;
180 size_t size;
181 size_t fsize;
182 int wrap;
183
184 fc->task = NULL;
185 GNUNET_assert (GNUNET_NO == fc->proc_busy);
186 if (0 == fc->acks)
187 return; /* all done */
188 /* calculate delay */
189 wrap = 0;
190 while (0 == (fc->acks & (1LLU << fc->next_transmission)))
191 {
192 fc->next_transmission = (fc->next_transmission + 1) % 64;
193 wrap |= (0 == fc->next_transmission);
194 }
195 bit = fc->next_transmission;
196 size = ntohs (fc->msg->size);
197 if (bit == size / (fc->mtu - sizeof(struct FragmentHeader)))
198 fsize =
199 (size % (fc->mtu - sizeof(struct FragmentHeader)))
200 + sizeof(struct FragmentHeader);
201 else
202 fsize = fc->mtu;
203 if (NULL != fc->tracker)
204 delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker,
205 fsize);
206 else
207 delay = GNUNET_TIME_UNIT_ZERO;
208 if (delay.rel_value_us > 0)
209 {
210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211 "Fragmentation logic delays transmission of next fragment by %s\n",
212 GNUNET_STRINGS_relative_time_to_string (delay,
213 GNUNET_YES));
214 fc->task = GNUNET_SCHEDULER_add_delayed (delay,
215 &transmit_next,
216 fc);
217 return;
218 }
219 fc->next_transmission = (fc->next_transmission + 1) % 64;
220 wrap |= (0 == fc->next_transmission);
221 while (0 == (fc->acks & (1LLU << fc->next_transmission)))
222 {
223 fc->next_transmission = (fc->next_transmission + 1) % 64;
224 wrap |= (0 == fc->next_transmission);
225 }
226
227 /* assemble fragmentation message */
228 mbuf = (const char *) &fc[1];
229 fh = (struct FragmentHeader *) msg;
230 fh->header.size = htons (fsize);
231 fh->header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT);
232 fh->fragment_id = htonl (fc->fragment_id);
233 fh->total_size = fc->msg->size; /* already in big-endian */
234 fh->offset = htons ((fc->mtu - sizeof(struct FragmentHeader)) * bit);
235 GNUNET_memcpy (&fh[1], &mbuf[bit * (fc->mtu - sizeof(struct FragmentHeader))],
236 fsize - sizeof(struct FragmentHeader));
237 if (NULL != fc->tracker)
238 GNUNET_BANDWIDTH_tracker_consume (fc->tracker, fsize);
239 GNUNET_STATISTICS_update (fc->stats,
240 _ ("# fragments transmitted"),
241 1,
242 GNUNET_NO);
243 if (0 != fc->last_round.abs_value_us)
244 GNUNET_STATISTICS_update (fc->stats,
245 _ ("# fragments retransmitted"),
246 1,
247 GNUNET_NO);
248
249 /* select next message to calculate delay */
250 bit = fc->next_transmission;
251 size = ntohs (fc->msg->size);
252 if (bit == size / (fc->mtu - sizeof(struct FragmentHeader)))
253 fsize = size % (fc->mtu - sizeof(struct FragmentHeader));
254 else
255 fsize = fc->mtu;
256 if (NULL != fc->tracker)
257 delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker,
258 fsize);
259 else
260 delay = GNUNET_TIME_UNIT_ZERO;
261 if (fc->num_rounds < 64)
262 delay = GNUNET_TIME_relative_max (delay,
263 GNUNET_TIME_relative_saturating_multiply
264 (fc->msg_delay,
265 (1ULL << fc->num_rounds)));
266 else
267 delay = GNUNET_TIME_UNIT_FOREVER_REL;
268 if (wrap)
269 {
270 /* full round transmitted wait 2x delay for ACK before going again */
271 fc->num_rounds++;
272 delay = GNUNET_TIME_relative_saturating_multiply (fc->ack_delay, 2);
273 /* never use zero, need some time for ACK always */
274 delay = GNUNET_TIME_relative_max (MIN_ACK_DELAY, delay);
275 fc->wack = GNUNET_YES;
276 fc->last_round = GNUNET_TIME_absolute_get ();
277 GNUNET_STATISTICS_update (fc->stats,
278 _ ("# fragments wrap arounds"),
279 1,
280 GNUNET_NO);
281 }
282 fc->proc_busy = GNUNET_YES;
283 fc->delay_until = GNUNET_TIME_relative_to_absolute (delay);
284 fc->num_transmissions++;
285 fc->proc (fc->proc_cls,
286 &fh->header);
287}
288
289
290/**
291 * Create a fragmentation context for the given message.
292 * Fragments the message into fragments of size @a mtu or
293 * less. Calls @a proc on each un-acknowledged fragment,
294 * using both the expected @a msg_delay between messages and
295 * acknowledgements and the given @a tracker to guide the
296 * frequency of calls to @a proc.
297 *
298 * @param stats statistics context
299 * @param mtu the maximum message size for each fragment
300 * @param tracker bandwidth tracker to use for flow control (can be NULL)
301 * @param msg_delay initial delay to insert between fragment transmissions
302 * based on previous messages
303 * @param ack_delay expected delay between fragment transmission
304 * and ACK based on previous messages
305 * @param msg the message to fragment
306 * @param proc function to call for each fragment to transmit
307 * @param proc_cls closure for @a proc
308 * @return the fragmentation context
309 */
310struct GNUNET_FRAGMENT_Context *
311GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats,
312 uint16_t mtu,
313 struct GNUNET_BANDWIDTH_Tracker *tracker,
314 struct GNUNET_TIME_Relative msg_delay,
315 struct GNUNET_TIME_Relative ack_delay,
316 const struct GNUNET_MessageHeader *msg,
317 GNUNET_FRAGMENT_MessageProcessor proc,
318 void *proc_cls)
319{
320 struct GNUNET_FRAGMENT_Context *fc;
321 size_t size;
322 uint64_t bits;
323
324 GNUNET_STATISTICS_update (stats,
325 _ ("# messages fragmented"),
326 1,
327 GNUNET_NO);
328 GNUNET_assert (mtu >= 1024 + sizeof(struct FragmentHeader));
329 size = ntohs (msg->size);
330 GNUNET_STATISTICS_update (stats,
331 _ ("# total size of fragmented messages"),
332 size, GNUNET_NO);
333 GNUNET_assert (size >= sizeof(struct GNUNET_MessageHeader));
334 fc = GNUNET_malloc (sizeof(struct GNUNET_FRAGMENT_Context) + size);
335 fc->stats = stats;
336 fc->mtu = mtu;
337 fc->tracker = tracker;
338 fc->ack_delay = ack_delay;
339 fc->msg_delay = msg_delay;
340 fc->msg = (const struct GNUNET_MessageHeader *) &fc[1];
341 fc->proc = proc;
342 fc->proc_cls = proc_cls;
343 fc->fragment_id =
344 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
345 UINT32_MAX);
346 GNUNET_memcpy (&fc[1], msg, size);
347 bits =
348 (size + mtu - sizeof(struct FragmentHeader) - 1) / (mtu
349 - sizeof(struct
350 FragmentHeader));
351 GNUNET_assert (bits <= 64);
352 if (bits == 64)
353 fc->acks_mask = UINT64_MAX; /* set all 64 bit */
354 else
355 fc->acks_mask = (1LLU << bits) - 1; /* set lowest 'bits' bit */
356 fc->acks = fc->acks_mask;
357 fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc);
358 return fc;
359}
360
361
362/**
363 * Continuation to call from the 'proc' function after the fragment
364 * has been transmitted (and hence the next fragment can now be
365 * given to proc).
366 *
367 * @param fc fragmentation context
368 */
369void
370GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc)
371{
372 GNUNET_assert (fc->proc_busy == GNUNET_YES);
373 fc->proc_busy = GNUNET_NO;
374 GNUNET_assert (fc->task == NULL);
375 fc->task =
376 GNUNET_SCHEDULER_add_at (fc->delay_until,
377 &transmit_next,
378 fc);
379}
380
381
382/**
383 * Process an acknowledgement message we got from the other
384 * side (to control re-transmits).
385 *
386 * @param fc fragmentation context
387 * @param msg acknowledgement message we received
388 * @return #GNUNET_OK if this ack completes the work of the 'fc'
389 * (all fragments have been received);
390 * #GNUNET_NO if more messages are pending
391 * #GNUNET_SYSERR if this ack is not valid for this fc
392 */
393int
394GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc,
395 const struct GNUNET_MessageHeader *msg)
396{
397 const struct FragmentAcknowledgement *fa;
398 uint64_t abits;
399 struct GNUNET_TIME_Relative ndelay;
400 unsigned int ack_cnt;
401 unsigned int snd_cnt;
402 unsigned int i;
403
404 if (sizeof(struct FragmentAcknowledgement) != ntohs (msg->size))
405 {
406 GNUNET_break_op (0);
407 return GNUNET_SYSERR;
408 }
409 fa = (const struct FragmentAcknowledgement *) msg;
410 if (ntohl (fa->fragment_id) != fc->fragment_id)
411 return GNUNET_SYSERR; /* not our ACK */
412 abits = GNUNET_ntohll (fa->bits);
413 if ((GNUNET_YES == fc->wack) &&
414 (0 != fc->num_transmissions))
415 {
416 /* normal ACK, can update running average of delay... */
417 fc->wack = GNUNET_NO;
418 ndelay = GNUNET_TIME_absolute_get_duration (fc->last_round);
419 fc->ack_delay.rel_value_us =
420 (ndelay.rel_value_us / fc->num_transmissions + 3
421 * fc->ack_delay.rel_value_us) / 4;
422 /* calculate ratio msg sent vs. msg acked */
423 ack_cnt = 0;
424 snd_cnt = 0;
425 for (i = 0; i < 64; i++)
426 {
427 if (1 == (fc->acks_mask & (1ULL << i)))
428 {
429 snd_cnt++;
430 if (0 == (abits & (1ULL << i)))
431 ack_cnt++;
432 }
433 }
434 if (0 == ack_cnt)
435 {
436 /* complete loss */
437 fc->msg_delay = GNUNET_TIME_relative_saturating_multiply (fc->msg_delay,
438 snd_cnt);
439 }
440 else if (snd_cnt > ack_cnt)
441 {
442 /* some loss, slow down proportionally */
443 fc->msg_delay.rel_value_us = ((fc->msg_delay.rel_value_us * ack_cnt)
444 / snd_cnt);
445 }
446 else if (snd_cnt == ack_cnt)
447 {
448 fc->msg_delay.rel_value_us =
449 (ndelay.rel_value_us / fc->num_transmissions + 3
450 * fc->msg_delay.rel_value_us) / 5;
451 }
452 fc->num_transmissions = 0;
453 fc->msg_delay = GNUNET_TIME_relative_min (fc->msg_delay,
454 GNUNET_TIME_UNIT_SECONDS);
455 fc->ack_delay = GNUNET_TIME_relative_min (fc->ack_delay,
456 GNUNET_TIME_UNIT_SECONDS);
457 }
458 GNUNET_STATISTICS_update (fc->stats,
459 _ ("# fragment acknowledgements received"),
460 1,
461 GNUNET_NO);
462 if (abits != (fc->acks & abits))
463 {
464 /* ID collision or message reordering, count! This should be rare! */
465 GNUNET_STATISTICS_update (fc->stats,
466 _ ("# bits removed from fragmentation ACKs"), 1,
467 GNUNET_NO);
468 }
469 fc->acks = abits & fc->acks_mask;
470 if (0 != fc->acks)
471 {
472 /* more to transmit, do so right now (if tracker permits...) */
473 if (fc->task != NULL)
474 {
475 /* schedule next transmission now, no point in waiting... */
476 GNUNET_SCHEDULER_cancel (fc->task);
477 fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc);
478 }
479 else
480 {
481 /* only case where there is no task should be if we're waiting
482 * for the right to transmit again (proc_busy set to YES) */
483 GNUNET_assert (GNUNET_YES == fc->proc_busy);
484 }
485 return GNUNET_NO;
486 }
487
488 /* all done */
489 GNUNET_STATISTICS_update (fc->stats,
490 _ ("# fragmentation transmissions completed"),
491 1,
492 GNUNET_NO);
493 if (NULL != fc->task)
494 {
495 GNUNET_SCHEDULER_cancel (fc->task);
496 fc->task = NULL;
497 }
498 return GNUNET_OK;
499}
500
501
502/**
503 * Destroy the given fragmentation context (stop calling 'proc', free
504 * resources).
505 *
506 * @param fc fragmentation context
507 * @param msg_delay where to store average delay between individual message transmissions the
508 * last message (OUT only)
509 * @param ack_delay where to store average delay between transmission and ACK for the
510 * last message, set to FOREVER if the message was not fully transmitted (OUT only)
511 */
512void
513GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc,
514 struct GNUNET_TIME_Relative *msg_delay,
515 struct GNUNET_TIME_Relative *ack_delay)
516{
517 if (fc->task != NULL)
518 GNUNET_SCHEDULER_cancel (fc->task);
519 if (NULL != ack_delay)
520 *ack_delay = fc->ack_delay;
521 if (NULL != msg_delay)
522 *msg_delay = GNUNET_TIME_relative_saturating_multiply (fc->msg_delay,
523 fc->num_rounds);
524 GNUNET_free (fc);
525}
526
527
528/* end of fragmentation.c */
diff --git a/src/fragmentation/fragmentation.h b/src/fragmentation/fragmentation.h
deleted file mode 100644
index 2d7abd4f7..000000000
--- a/src/fragmentation/fragmentation.h
+++ /dev/null
@@ -1,85 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2011 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/fragmentation/fragmentation.h
22 * @brief library to help fragment messages
23 * @author Christian Grothoff
24 */
25#ifndef FRAGMENTATION_H
26#define FRAGMENTATION_H
27#include "platform.h"
28#include "gnunet_fragmentation_lib.h"
29
30GNUNET_NETWORK_STRUCT_BEGIN
31
32/**
33 * Header for a message fragment. Followed by the
34 * original message.
35 */
36struct FragmentHeader
37{
38 /**
39 * Message header.
40 */
41 struct GNUNET_MessageHeader header;
42
43 /**
44 * Unique fragment ID.
45 */
46 uint32_t fragment_id GNUNET_PACKED;
47
48 /**
49 * Total message size of the original message.
50 */
51 uint16_t total_size GNUNET_PACKED;
52
53 /**
54 * Absolute offset (in bytes) of this fragment in the original
55 * message. Will be a multiple of the MTU.
56 */
57 uint16_t offset GNUNET_PACKED;
58};
59
60
61/**
62 * Message fragment acknowledgement.
63 */
64struct FragmentAcknowledgement
65{
66 /**
67 * Message header.
68 */
69 struct GNUNET_MessageHeader header;
70
71 /**
72 * Unique fragment ID.
73 */
74 uint32_t fragment_id GNUNET_PACKED;
75
76 /**
77 * Bits that are being acknowledged, in big-endian.
78 * (bits that are set correspond to fragments that
79 * have not yet been received).
80 */
81 uint64_t bits GNUNET_PACKED;
82};
83GNUNET_NETWORK_STRUCT_END
84
85#endif
diff --git a/src/fragmentation/test_fragmentation.c b/src/fragmentation/test_fragmentation.c
deleted file mode 100644
index 77879f75b..000000000
--- a/src/fragmentation/test_fragmentation.c
+++ /dev/null
@@ -1,303 +0,0 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
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
45static int ret = 1;
46
47static unsigned int dups;
48
49static unsigned int fragc;
50
51static unsigned int frag_drops;
52
53static unsigned int acks;
54
55static unsigned int ack_drops;
56
57static struct GNUNET_DEFRAGMENT_Context *defrag;
58
59static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS];
60
61static struct GNUNET_FRAGMENT_Context *frag;
62
63static struct GNUNET_SCHEDULER_Task *shutdown_task;
64
65static struct GNUNET_TIME_Relative msg_delay;
66
67static struct GNUNET_TIME_Relative ack_delay;
68
69
70static void
71do_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
93static void
94proc_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, e.g. 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 */
123static void
124proc_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
161static void
162next_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 */
203static void
204proc_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 "); /* duplicate 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 */
251static void
252run (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
266int
267main (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}
diff --git a/src/fragmentation/test_fragmentation_data.conf b/src/fragmentation/test_fragmentation_data.conf
deleted file mode 100644
index 54ad21ff9..000000000
--- a/src/fragmentation/test_fragmentation_data.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1
2[nse]
3START_ON_DEMAND = NO
4
5
diff --git a/src/fragmentation/test_fragmentation_parallel.c b/src/fragmentation/test_fragmentation_parallel.c
deleted file mode 100644
index d19296cf5..000000000
--- a/src/fragmentation/test_fragmentation_parallel.c
+++ /dev/null
@@ -1,254 +0,0 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
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 500
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 5
44
45static int ret = 1;
46
47static unsigned int dups;
48
49static unsigned int fragc;
50
51static unsigned int frag_drops;
52
53static unsigned int acks;
54
55static unsigned int ack_drops;
56
57static struct GNUNET_DEFRAGMENT_Context *defrag;
58
59static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS];
60
61static struct GNUNET_FRAGMENT_Context *frags[NUM_MSGS];
62
63static struct GNUNET_SCHEDULER_Task *shutdown_task;
64
65
66static void
67do_shutdown (void *cls)
68{
69 unsigned int i;
70
71 ret = 0;
72 shutdown_task = NULL;
73 GNUNET_DEFRAGMENT_context_destroy (defrag);
74 defrag = NULL;
75 for (i = 0; i < NUM_MSGS; i++)
76 {
77 if (frags[i] == NULL)
78 continue;
79 GNUNET_FRAGMENT_context_destroy (frags[i], NULL, NULL);
80 frags[i] = NULL;
81 }
82}
83
84
85static void
86proc_msgs (void *cls, const struct GNUNET_MessageHeader *hdr)
87{
88 static unsigned int total;
89 unsigned int i;
90 const char *buf;
91
92#if DETAILS
93 fprintf (stderr, "%s", "!"); /* message complete, good! */
94#endif
95 buf = (const char *) hdr;
96 for (i = sizeof(struct GNUNET_MessageHeader); i < ntohs (hdr->size); i++)
97 GNUNET_assert (buf[i] == (char) i);
98 total++;
99#if ! DETAILS
100 if (0 == (total % (NUM_MSGS / 100)))
101 fprintf (stderr, "%s", ".");
102#endif
103 /* tolerate 10% loss, e.g due to duplicate fragment IDs */
104 if ((total >= NUM_MSGS - (NUM_MSGS / 10)) && (ret != 0))
105 {
106 if (NULL == shutdown_task)
107 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
108 }
109}
110
111
112/**
113 * Process ACK (by passing to fragmenter)
114 */
115static void
116proc_acks (void *cls, uint32_t msg_id, const struct GNUNET_MessageHeader *hdr)
117{
118 unsigned int i;
119 int ret;
120
121 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
122 {
123 ack_drops++;
124 return; /* random drop */
125 }
126 for (i = 0; i < NUM_MSGS; i++)
127 {
128 if (frags[i] == NULL)
129 continue;
130 ret = GNUNET_FRAGMENT_process_ack (frags[i], hdr);
131 if (ret == GNUNET_OK)
132 {
133#if DETAILS
134 fprintf (stderr, "%s", "@"); /* good ACK */
135#endif
136 GNUNET_FRAGMENT_context_destroy (frags[i], NULL, NULL);
137 frags[i] = NULL;
138 acks++;
139 return;
140 }
141 if (ret == GNUNET_NO)
142 {
143#if DETAILS
144 fprintf (stderr, "%s", "@"); /* good ACK */
145#endif
146 acks++;
147 return;
148 }
149 }
150#if DETAILS
151 fprintf (stderr, "%s", "_"); /* BAD: ack that nobody feels responsible for... */
152#endif
153}
154
155
156/**
157 * Process fragment (by passing to defrag).
158 */
159static void
160proc_frac (void *cls, const struct GNUNET_MessageHeader *hdr)
161{
162 struct GNUNET_FRAGMENT_Context **fc = cls;
163 int ret;
164
165 GNUNET_FRAGMENT_context_transmission_done (*fc);
166 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE))
167 {
168 frag_drops++;
169 return; /* random drop */
170 }
171 if (NULL == defrag)
172 {
173 fprintf (stderr, "%s", "E"); /* Error: frag after shutdown!? */
174 return;
175 }
176 ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr);
177 if (ret == GNUNET_NO)
178 {
179#if DETAILS
180 fprintf (stderr, "%s", "?"); /* duplicate fragment */
181#endif
182 dups++;
183 }
184 else if (ret == GNUNET_OK)
185 {
186#if DETAILS
187 fprintf (stderr, "%s", "."); /* good fragment */
188#endif
189 fragc++;
190 }
191}
192
193
194/**
195 * Main function run with scheduler.
196 */
197static void
198run (void *cls, char *const *args, const char *cfgfile,
199 const struct GNUNET_CONFIGURATION_Handle *cfg)
200{
201 unsigned int i;
202 struct GNUNET_MessageHeader *msg;
203 char buf[MTU + 32 * 1024];
204
205 defrag = GNUNET_DEFRAGMENT_context_create (NULL, MTU, NUM_MSGS /* enough space for all */
206 , NULL, &proc_msgs, &proc_acks);
207 for (i = 0; i < sizeof(buf); i++)
208 buf[i] = (char) i;
209 msg = (struct GNUNET_MessageHeader *) buf;
210 for (i = 0; i < NUM_MSGS; i++)
211 {
212 msg->type = htons ((uint16_t) i);
213 msg->size =
214 htons (sizeof(struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024));
215 frags[i] = GNUNET_FRAGMENT_context_create (NULL /* no stats */,
216 MTU, &trackers[i],
217 GNUNET_TIME_UNIT_MILLISECONDS,
218 GNUNET_TIME_UNIT_SECONDS,
219 msg,
220 &proc_frac, &frags[i]);
221 }
222}
223
224
225int
226main (int argc, char *argv[])
227{
228 struct GNUNET_GETOPT_CommandLineOption options[] = {
229 GNUNET_GETOPT_OPTION_END
230 };
231 char *const argv_prog[] = {
232 "test-fragmentation",
233 "-c",
234 "test_fragmentation_data.conf",
235 "-L",
236 "WARNING",
237 NULL
238 };
239 unsigned int i;
240
241 GNUNET_log_setup ("test-fragmentation",
242 "WARNING",
243 NULL);
244 for (i = 0; i < NUM_MSGS; i++)
245 GNUNET_BANDWIDTH_tracker_init (&trackers[i], NULL, NULL,
246 GNUNET_BANDWIDTH_value_init ((i + 1) * 1024),
247 100);
248 GNUNET_PROGRAM_run (5, argv_prog, "test-fragmentation", "nohelp", options,
249 &run, NULL);
250 fprintf (stderr,
251 "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n",
252 fragc, dups, acks, ack_drops);
253 return ret;
254}