GNUnet  0.10.x
defragmentation.c
Go to the documentation of this file.
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 */
25 #include "platform.h"
27 #include "fragmentation.h"
28 
32 struct FragTimes
33 {
38 
42  unsigned int bit;
43 };
44 
45 
53 {
58 
63 
68 
73  const struct GNUNET_MessageHeader *msg;
74 
80  struct GNUNET_TIME_Absolute last_update;
81 
87 
92  struct FragTimes frag_times[64];
93 
98  uint64_t bits;
99 
103  uint32_t fragment_id;
104 
108  unsigned int last_bit;
109 
115 
121 
125  uint16_t total_size;
126 
130  int16_t last_duplicate;
131 
132 };
133 
134 
139 {
140 
145 
150 
155 
159  void *cls;
160 
165 
170 
175  struct GNUNET_TIME_Relative latency;
176 
181  unsigned int num_msgs;
182 
187  unsigned int list_size;
188 
192  uint16_t mtu;
193 
194 };
195 
196 
212  uint16_t mtu, unsigned int num_msgs,
213  void *cls,
216 {
218 
220  dc->stats = stats;
221  dc->cls = cls;
222  dc->proc = proc;
223  dc->ackp = ackp;
224  dc->num_msgs = num_msgs;
225  dc->mtu = mtu;
226  dc->latency = GNUNET_TIME_UNIT_SECONDS; /* start with likely overestimate */
227  return dc;
228 }
229 
230 
236 void
238 {
239  struct MessageContext *mc;
240 
241  while (NULL != (mc = dc->head))
242  {
243  GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, mc);
244  dc->list_size--;
245  if (NULL != mc->ack_task)
246  {
248  mc->ack_task = NULL;
249  }
250  GNUNET_free (mc);
251  }
252  GNUNET_assert (0 == dc->list_size);
253  GNUNET_free (dc);
254 }
255 
256 
262 static void
263 send_ack (void *cls)
264 {
265  struct MessageContext *mc = cls;
266  struct GNUNET_DEFRAGMENT_Context *dc = mc->dc;
267  struct FragmentAcknowledgement fa;
268 
269  mc->ack_task = NULL;
270  fa.header.size = htons (sizeof (struct FragmentAcknowledgement));
272  fa.fragment_id = htonl (mc->fragment_id);
273  fa.bits = GNUNET_htonll (mc->bits);
275  _("# acknowledgements sent for fragment"),
276  1,
277  GNUNET_NO);
278  mc->last_duplicate = GNUNET_NO; /* clear flag */
279  dc->ackp (dc->cls,
280  mc->fragment_id,
281  &fa.header);
282 }
283 
284 
289 static void
290 gsl_fit_mul (const double *x, const size_t xstride, const double *y,
291  const size_t ystride, const size_t n, double *c1, double *cov_11,
292  double *sumsq)
293 {
294  double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0;
295 
296  size_t i;
297 
298  for (i = 0; i < n; i++)
299  {
300  m_x += (x[i * xstride] - m_x) / (i + 1.0);
301  m_y += (y[i * ystride] - m_y) / (i + 1.0);
302  }
303 
304  for (i = 0; i < n; i++)
305  {
306  const double dx = x[i * xstride] - m_x;
307  const double dy = y[i * ystride] - m_y;
308 
309  m_dx2 += (dx * dx - m_dx2) / (i + 1.0);
310  m_dxdy += (dx * dy - m_dxdy) / (i + 1.0);
311  }
312 
313  /* In terms of y = b x */
314 
315  {
316  double s2 = 0, d2 = 0;
317  double b = (m_x * m_y + m_dxdy) / (m_x * m_x + m_dx2);
318 
319  *c1 = b;
320 
321  /* Compute chi^2 = \sum (y_i - b * x_i)^2 */
322 
323  for (i = 0; i < n; i++)
324  {
325  const double dx = x[i * xstride] - m_x;
326  const double dy = y[i * ystride] - m_y;
327  const double d = (m_y - b * m_x) + dy - b * dx;
328 
329  d2 += d * d;
330  }
331 
332  s2 = d2 / (n - 1.0); /* chisq per degree of freedom */
333 
334  *cov_11 = s2 * 1.0 / (n * (m_x * m_x + m_dx2));
335 
336  *sumsq = d2;
337  }
338 }
339 
340 
348 static struct GNUNET_TIME_Relative
350 {
351  struct FragTimes *first;
352  size_t total = mc->frag_times_write_offset - mc->frag_times_start_offset;
353  double x[total];
354  double y[total];
355  size_t i;
356  double c1;
357  double cov11;
358  double sumsq;
359  struct GNUNET_TIME_Relative ret;
360 
361  first = &mc->frag_times[mc->frag_times_start_offset];
362  GNUNET_assert (total > 1);
363  for (i = 0; i < total; i++)
364  {
365  x[i] = (double) i;
366  y[i] = (double) (first[i].time.abs_value_us - first[0].time.abs_value_us);
367  }
368  gsl_fit_mul (x, 1, y, 1, total, &c1, &cov11, &sumsq);
369  c1 += sqrt (sumsq); /* add 1 std dev */
370  ret.rel_value_us = (uint64_t) c1;
371  if (0 == ret.rel_value_us)
372  ret = GNUNET_TIME_UNIT_MICROSECONDS; /* always at least 1 */
373  return ret;
374 }
375 
376 
382 static void
384 {
385  struct MessageContext *old;
386  struct MessageContext *pos;
387 
388  old = NULL;
389  pos = dc->head;
390  while (NULL != pos)
391  {
392  if ((old == NULL) ||
394  old = pos;
395  pos = pos->next;
396  }
397  GNUNET_assert (NULL != old);
398  GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, old);
399  dc->list_size--;
400  if (NULL != old->ack_task)
401  {
403  old->ack_task = NULL;
404  }
405  GNUNET_free (old);
406 }
407 
408 
418 int
420  const struct GNUNET_MessageHeader *msg)
421 {
422  struct MessageContext *mc;
423  const struct FragmentHeader *fh;
424  uint16_t msize;
425  uint16_t foff;
426  uint32_t fid;
427  char *mbuf;
428  unsigned int bit;
429  struct GNUNET_TIME_Absolute now;
430  struct GNUNET_TIME_Relative delay;
431  unsigned int bc;
432  unsigned int b;
433  unsigned int n;
434  unsigned int num_fragments;
435  int duplicate;
436  int last;
437 
438  if (ntohs (msg->size) < sizeof (struct FragmentHeader))
439  {
440  GNUNET_break_op (0);
441  return GNUNET_SYSERR;
442  }
443  if (ntohs (msg->size) > dc->mtu)
444  {
445  GNUNET_break_op (0);
446  return GNUNET_SYSERR;
447  }
448  fh = (const struct FragmentHeader *) msg;
449  msize = ntohs (fh->total_size);
450  if (msize < sizeof (struct GNUNET_MessageHeader))
451  {
452  GNUNET_break_op (0);
453  return GNUNET_SYSERR;
454  }
455  fid = ntohl (fh->fragment_id);
456  foff = ntohs (fh->offset);
457  if (foff >= msize)
458  {
459  GNUNET_break_op (0);
460  return GNUNET_SYSERR;
461  }
462  if (0 != (foff % (dc->mtu - sizeof (struct FragmentHeader))))
463  {
464  GNUNET_break_op (0);
465  return GNUNET_SYSERR;
466  }
468  _("# fragments received"),
469  1,
470  GNUNET_NO);
471  num_fragments = (ntohs (msg->size) + dc->mtu - sizeof (struct FragmentHeader)-1) / (dc->mtu - sizeof (struct FragmentHeader));
472  last = 0;
473  for (mc = dc->head; NULL != mc; mc = mc->next)
474  if (mc->fragment_id > fid)
475  last++;
476 
477  mc = dc->head;
478  while ((NULL != mc) && (fid != mc->fragment_id))
479  mc = mc->next;
480  bit = foff / (dc->mtu - sizeof (struct FragmentHeader));
481  if (bit * (dc->mtu - sizeof (struct FragmentHeader)) + ntohs (msg->size) -
482  sizeof (struct FragmentHeader) > msize)
483  {
484  /* payload extends past total message size */
485  GNUNET_break_op (0);
486  return GNUNET_SYSERR;
487  }
488  if ((NULL != mc) && (msize != mc->total_size))
489  {
490  /* inconsistent message size */
491  GNUNET_break_op (0);
492  return GNUNET_SYSERR;
493  }
494  now = GNUNET_TIME_absolute_get ();
495  if (NULL == mc)
496  {
497  mc = GNUNET_malloc (sizeof (struct MessageContext) + msize);
498  mc->msg = (const struct GNUNET_MessageHeader *) &mc[1];
499  mc->dc = dc;
500  mc->total_size = msize;
501  mc->fragment_id = fid;
502  mc->last_update = now;
503  n = (msize + dc->mtu - sizeof (struct FragmentHeader) - 1) / (dc->mtu -
504  sizeof (struct
505  FragmentHeader));
506  if (n == 64)
507  mc->bits = UINT64_MAX; /* set all 64 bit */
508  else
509  mc->bits = (1LLU << n) - 1; /* set lowest 'bits' bit */
510  if (dc->list_size >= dc->num_msgs)
511  discard_oldest_mc (dc);
512  GNUNET_CONTAINER_DLL_insert (dc->head,
513  dc->tail,
514  mc);
515  dc->list_size++;
516  }
517 
518  /* copy data to 'mc' */
519  if (0 != (mc->bits & (1LLU << bit)))
520  {
521  mc->bits -= 1LLU << bit;
522  mbuf = (char *) &mc[1];
523  GNUNET_memcpy (&mbuf[bit * (dc->mtu - sizeof (struct FragmentHeader))], &fh[1],
524  ntohs (msg->size) - sizeof (struct FragmentHeader));
525  mc->last_update = now;
526  if (bit < mc->last_bit)
528  mc->last_bit = bit;
529  mc->frag_times[mc->frag_times_write_offset].time = now;
532  duplicate = GNUNET_NO;
533  }
534  else
535  {
536  duplicate = GNUNET_YES;
537  GNUNET_STATISTICS_update (dc->stats,
538  _("# duplicate fragments received"),
539  1,
540  GNUNET_NO);
541  }
542 
543  /* count number of missing fragments after the current one */
544  bc = 0;
545  for (b = bit; b < 64; b++)
546  if (0 != (mc->bits & (1LLU << b)))
547  bc++;
548  else
549  bc = 0;
550 
551  /* notify about complete message */
552  if ( (GNUNET_NO == duplicate) &&
553  (0 == mc->bits) )
554  {
555  GNUNET_STATISTICS_update (dc->stats,
556  _("# messages defragmented"),
557  1,
558  GNUNET_NO);
559  /* message complete, notify! */
560  dc->proc (dc->cls, mc->msg);
561  }
562  /* send ACK */
564  {
565  dc->latency = estimate_latency (mc);
566  }
567  delay = GNUNET_TIME_relative_saturating_multiply (dc->latency,
568  bc + 1);
569  if ( (last + fid == num_fragments) ||
570  (0 == mc->bits) ||
571  (GNUNET_YES == duplicate) )
572  {
573  /* message complete or duplicate or last missing fragment in
574  linear sequence; ACK now! */
575  delay = GNUNET_TIME_UNIT_ZERO;
576  }
577  if (NULL != mc->ack_task)
580  &send_ack,
581  mc);
582  if (GNUNET_YES == duplicate)
583  {
585  return GNUNET_NO;
586  }
587  return GNUNET_YES;
588 }
589 
590 /* end of defragmentation.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static struct GNUNET_STATISTICS_Handle * stats
Handle for statistics.
uint32_t fragment_id
Unique fragment ID.
Definition: fragmentation.h:77
struct MessageContext * tail
Tail of list of messages we&#39;re defragmenting.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
uint32_t fragment_id
Unique fragment ID.
Definition: fragmentation.h:47
uint64_t rel_value_us
The actual value.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
unsigned int frag_times_start_offset
For the current ACK round, which is the first relevant offset in frag_times?
uint64_t bits
Bits that are being acknowledged, in big-endian.
Definition: fragmentation.h:84
struct GNUNET_SCHEDULER_Task * ack_task
Task scheduled for transmitting the next ACK to the other peer.
static void send_ack(void *cls)
Send acknowledgement to the other peer now.
struct GNUNET_DEFRAGMENT_Context * GNUNET_DEFRAGMENT_context_create(struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, unsigned int num_msgs, void *cls, GNUNET_FRAGMENT_MessageProcessor proc, GNUNET_DEFRAGMENT_AckProcessor ackp)
Create a defragmentation context.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_TIME_UNIT_SECONDS
One second.
static void gsl_fit_mul(const double *x, const size_t xstride, const double *y, const size_t ystride, const size_t n, double *c1, double *cov_11, double *sumsq)
This function is from the GNU Scientific Library, linear/fit.c, Copyright (C) 2000 Brian Gough...
library to help fragment messages
void(* GNUNET_FRAGMENT_MessageProcessor)(void *cls, const struct GNUNET_MessageHeader *msg)
Function that is called with messages created by the fragmentation module.
uint64_t bits
Which fragments have we gotten yet? bits that are 1 indicate missing fragments.
uint16_t total_size
Total message size of the original message.
Definition: fragmentation.h:52
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Timestamps for fragments.
void * cls
Closure for proc and ackp.
struct GNUNET_MessageHeader header
Message header.
Definition: fragmentation.h:72
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
static int ret
Final status code.
Definition: gnunet-arm.c:89
Handle for the service.
struct GNUNET_TIME_Absolute last_update
Last time we received any update for this message (least-recently updated message will be discarded i...
#define GNUNET_MESSAGE_TYPE_FRAGMENT_ACK
Acknowledgement of a FRAGMENT of a larger message.
uint64_t abs_value_us
The actual value.
uint16_t total_size
Total size of the message that we are assembling.
unsigned int list_size
Current number of messages in the &#39;struct MessageContext&#39; DLL (smaller or equal to &#39;num_msgs&#39;)...
struct GNUNET_TIME_Absolute time
The time the fragment was received.
GNUNET_DEFRAGMENT_AckProcessor ackp
Function to call with acknowledgements.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
unsigned int num_msgs
num_msgs how many fragmented messages to we defragment at most at the same time?
struct MessageContext * head
Head of list of messages we&#39;re defragmenting.
struct MessageContext * prev
This is a DLL.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1246
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
Information we keep for one message that is being assembled.
#define GNUNET_memcpy(dst, src, n)
void GNUNET_DEFRAGMENT_context_destroy(struct GNUNET_DEFRAGMENT_Context *dc)
Destroy the given defragmentation context.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
struct FragTimes frag_times[64]
When did we receive which fragment? Used to calculate the time we should send the ACK...
unsigned int last_bit
Which &#39;bit&#39; did the last fragment we received correspond to?
static int fh
Handle to the unique file.
uint32_t fragment_id
Unique ID for this message.
static struct GNUNET_TESTBED_Controller * mc
Handle to the master controller.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
int16_t last_duplicate
Was the last fragment we got a duplicate?
struct GNUNET_DEFRAGMENT_Context * dc
Associated defragmentation context.
Defragmentation context (one per connection).
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:35
struct GNUNET_STATISTICS_Handle * stats
For statistics.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
uint16_t offset
Absolute offset (in bytes) of this fragment in the original message.
Definition: fragmentation.h:58
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
struct GNUNET_TIME_Relative latency
Running average of the latency (delay between messages) for this connection.
static void discard_oldest_mc(struct GNUNET_DEFRAGMENT_Context *dc)
Discard the message context that was inactive for the longest time.
struct MessageContext * next
This is a DLL.
GNUNET_FRAGMENT_MessageProcessor proc
Function to call with defragmented messages.
unsigned int bit
Number of the bit for the fragment (in [0,..,63]).
Message fragment acknowledgement.
Definition: fragmentation.h:66
Entry in list of pending tasks.
Definition: scheduler.c:134
const struct GNUNET_MessageHeader * msg
Pointer to the assembled message, allocated at the end of this struct.
static struct GNUNET_TIME_Relative estimate_latency(struct MessageContext *mc)
Estimate the latency between messages based on the most recent message time stamps.
Header for all communications.
int GNUNET_DEFRAGMENT_process_fragment(struct GNUNET_DEFRAGMENT_Context *dc, const struct GNUNET_MessageHeader *msg)
We have received a fragment.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
uint16_t mtu
Maximum message size for each fragment.
unsigned int frag_times_write_offset
Which offset whould we write the next frag value into in the frag_times array? All smaller entries ar...
#define GNUNET_TIME_UNIT_MICROSECONDS
One microsecond, our basic time unit.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_saturating_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Saturating multiply relative time by a given factor.
Definition: time.c:499
void(* GNUNET_DEFRAGMENT_AckProcessor)(void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg)
Function that is called with acknowledgement messages created by the fragmentation module...
#define GNUNET_malloc(size)
Wrapper around malloc.
static struct GNUNET_FS_DownloadContext * dc
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
Header for a message fragment.
Definition: fragmentation.h:36
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965