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 {
37 
41  unsigned int bit;
42 };
43 
44 
56 
61 
66 
71  const struct GNUNET_MessageHeader *msg;
72 
78  struct GNUNET_TIME_Absolute last_update;
79 
85 
90  struct FragTimes frag_times[64];
91 
96  uint64_t bits;
97 
101  uint32_t fragment_id;
102 
106  unsigned int last_bit;
107 
113 
119 
123  uint16_t total_size;
124 
128  int16_t last_duplicate;
129 };
130 
131 
140 
145 
150 
154  void *cls;
155 
160 
165 
170  struct GNUNET_TIME_Relative latency;
171 
176  unsigned int num_msgs;
177 
182  unsigned int list_size;
183 
187  uint16_t mtu;
188 };
189 
190 
206  uint16_t mtu, unsigned int num_msgs,
207  void *cls,
210 {
212 
214  dc->stats = stats;
215  dc->cls = cls;
216  dc->proc = proc;
217  dc->ackp = ackp;
218  dc->num_msgs = num_msgs;
219  dc->mtu = mtu;
220  dc->latency = GNUNET_TIME_UNIT_SECONDS; /* start with likely overestimate */
221  return dc;
222 }
223 
224 
230 void
232 {
233  struct MessageContext *mc;
234 
235  while (NULL != (mc = dc->head))
236  {
237  GNUNET_CONTAINER_DLL_remove(dc->head, dc->tail, mc);
238  dc->list_size--;
239  if (NULL != mc->ack_task)
240  {
242  mc->ack_task = NULL;
243  }
244  GNUNET_free(mc);
245  }
246  GNUNET_assert(0 == dc->list_size);
247  GNUNET_free(dc);
248 }
249 
250 
256 static void
257 send_ack(void *cls)
258 {
259  struct MessageContext *mc = cls;
260  struct GNUNET_DEFRAGMENT_Context *dc = mc->dc;
261  struct FragmentAcknowledgement fa;
262 
263  mc->ack_task = NULL;
264  fa.header.size = htons(sizeof(struct FragmentAcknowledgement));
266  fa.fragment_id = htonl(mc->fragment_id);
267  fa.bits = GNUNET_htonll(mc->bits);
269  _("# acknowledgements sent for fragment"),
270  1,
271  GNUNET_NO);
272  mc->last_duplicate = GNUNET_NO; /* clear flag */
273  dc->ackp(dc->cls,
274  mc->fragment_id,
275  &fa.header);
276 }
277 
278 
283 static void
284 gsl_fit_mul(const double *x, const size_t xstride, const double *y,
285  const size_t ystride, const size_t n, double *c1, double *cov_11,
286  double *sumsq)
287 {
288  double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0;
289 
290  size_t i;
291 
292  for (i = 0; i < n; i++)
293  {
294  m_x += (x[i * xstride] - m_x) / (i + 1.0);
295  m_y += (y[i * ystride] - m_y) / (i + 1.0);
296  }
297 
298  for (i = 0; i < n; i++)
299  {
300  const double dx = x[i * xstride] - m_x;
301  const double dy = y[i * ystride] - m_y;
302 
303  m_dx2 += (dx * dx - m_dx2) / (i + 1.0);
304  m_dxdy += (dx * dy - m_dxdy) / (i + 1.0);
305  }
306 
307  /* In terms of y = b x */
308 
309  {
310  double s2 = 0, d2 = 0;
311  double b = (m_x * m_y + m_dxdy) / (m_x * m_x + m_dx2);
312 
313  *c1 = b;
314 
315  /* Compute chi^2 = \sum (y_i - b * x_i)^2 */
316 
317  for (i = 0; i < n; i++)
318  {
319  const double dx = x[i * xstride] - m_x;
320  const double dy = y[i * ystride] - m_y;
321  const double d = (m_y - b * m_x) + dy - b * dx;
322 
323  d2 += d * d;
324  }
325 
326  s2 = d2 / (n - 1.0); /* chisq per degree of freedom */
327 
328  *cov_11 = s2 * 1.0 / (n * (m_x * m_x + m_dx2));
329 
330  *sumsq = d2;
331  }
332 }
333 
334 
342 static struct GNUNET_TIME_Relative
344 {
345  struct FragTimes *first;
346  size_t total = mc->frag_times_write_offset - mc->frag_times_start_offset;
347  double x[total];
348  double y[total];
349  size_t i;
350  double c1;
351  double cov11;
352  double sumsq;
353  struct GNUNET_TIME_Relative ret;
354 
355  first = &mc->frag_times[mc->frag_times_start_offset];
356  GNUNET_assert(total > 1);
357  for (i = 0; i < total; i++)
358  {
359  x[i] = (double)i;
360  y[i] = (double)(first[i].time.abs_value_us - first[0].time.abs_value_us);
361  }
362  gsl_fit_mul(x, 1, y, 1, total, &c1, &cov11, &sumsq);
363  c1 += sqrt(sumsq); /* add 1 std dev */
364  ret.rel_value_us = (uint64_t)c1;
365  if (0 == ret.rel_value_us)
366  ret = GNUNET_TIME_UNIT_MICROSECONDS; /* always at least 1 */
367  return ret;
368 }
369 
370 
376 static void
378 {
379  struct MessageContext *old;
380  struct MessageContext *pos;
381 
382  old = NULL;
383  pos = dc->head;
384  while (NULL != pos)
385  {
386  if ((old == NULL) ||
388  old = pos;
389  pos = pos->next;
390  }
391  GNUNET_assert(NULL != old);
392  GNUNET_CONTAINER_DLL_remove(dc->head, dc->tail, old);
393  dc->list_size--;
394  if (NULL != old->ack_task)
395  {
397  old->ack_task = NULL;
398  }
399  GNUNET_free(old);
400 }
401 
402 
412 int
414  const struct GNUNET_MessageHeader *msg)
415 {
416  struct MessageContext *mc;
417  const struct FragmentHeader *fh;
418  uint16_t msize;
419  uint16_t foff;
420  uint32_t fid;
421  char *mbuf;
422  unsigned int bit;
423  struct GNUNET_TIME_Absolute now;
424  struct GNUNET_TIME_Relative delay;
425  unsigned int bc;
426  unsigned int b;
427  unsigned int n;
428  unsigned int num_fragments;
429  int duplicate;
430  int last;
431 
432  if (ntohs(msg->size) < sizeof(struct FragmentHeader))
433  {
434  GNUNET_break_op(0);
435  return GNUNET_SYSERR;
436  }
437  if (ntohs(msg->size) > dc->mtu)
438  {
439  GNUNET_break_op(0);
440  return GNUNET_SYSERR;
441  }
442  fh = (const struct FragmentHeader *)msg;
443  msize = ntohs(fh->total_size);
444  if (msize < sizeof(struct GNUNET_MessageHeader))
445  {
446  GNUNET_break_op(0);
447  return GNUNET_SYSERR;
448  }
449  fid = ntohl(fh->fragment_id);
450  foff = ntohs(fh->offset);
451  if (foff >= msize)
452  {
453  GNUNET_break_op(0);
454  return GNUNET_SYSERR;
455  }
456  if (0 != (foff % (dc->mtu - sizeof(struct FragmentHeader))))
457  {
458  GNUNET_break_op(0);
459  return GNUNET_SYSERR;
460  }
462  _("# fragments received"),
463  1,
464  GNUNET_NO);
465  num_fragments = (ntohs(msg->size) + dc->mtu - sizeof(struct FragmentHeader) - 1) / (dc->mtu - sizeof(struct FragmentHeader));
466  last = 0;
467  for (mc = dc->head; NULL != mc; mc = mc->next)
468  if (mc->fragment_id > fid)
469  last++;
470 
471  mc = dc->head;
472  while ((NULL != mc) && (fid != mc->fragment_id))
473  mc = mc->next;
474  bit = foff / (dc->mtu - sizeof(struct FragmentHeader));
475  if (bit * (dc->mtu - sizeof(struct FragmentHeader)) + ntohs(msg->size) -
476  sizeof(struct FragmentHeader) > msize)
477  {
478  /* payload extends past total message size */
479  GNUNET_break_op(0);
480  return GNUNET_SYSERR;
481  }
482  if ((NULL != mc) && (msize != mc->total_size))
483  {
484  /* inconsistent message size */
485  GNUNET_break_op(0);
486  return GNUNET_SYSERR;
487  }
488  now = GNUNET_TIME_absolute_get();
489  if (NULL == mc)
490  {
491  mc = GNUNET_malloc(sizeof(struct MessageContext) + msize);
492  mc->msg = (const struct GNUNET_MessageHeader *)&mc[1];
493  mc->dc = dc;
494  mc->total_size = msize;
495  mc->fragment_id = fid;
496  mc->last_update = now;
497  n = (msize + dc->mtu - sizeof(struct FragmentHeader) - 1) / (dc->mtu -
498  sizeof(struct
499  FragmentHeader));
500  if (n == 64)
501  mc->bits = UINT64_MAX; /* set all 64 bit */
502  else
503  mc->bits = (1LLU << n) - 1; /* set lowest 'bits' bit */
504  if (dc->list_size >= dc->num_msgs)
505  discard_oldest_mc(dc);
507  dc->tail,
508  mc);
509  dc->list_size++;
510  }
511 
512  /* copy data to 'mc' */
513  if (0 != (mc->bits & (1LLU << bit)))
514  {
515  mc->bits -= 1LLU << bit;
516  mbuf = (char *)&mc[1];
517  GNUNET_memcpy(&mbuf[bit * (dc->mtu - sizeof(struct FragmentHeader))], &fh[1],
518  ntohs(msg->size) - sizeof(struct FragmentHeader));
519  mc->last_update = now;
520  if (bit < mc->last_bit)
522  mc->last_bit = bit;
523  mc->frag_times[mc->frag_times_write_offset].time = now;
526  duplicate = GNUNET_NO;
527  }
528  else
529  {
530  duplicate = GNUNET_YES;
531  GNUNET_STATISTICS_update(dc->stats,
532  _("# duplicate fragments received"),
533  1,
534  GNUNET_NO);
535  }
536 
537  /* count number of missing fragments after the current one */
538  bc = 0;
539  for (b = bit; b < 64; b++)
540  if (0 != (mc->bits & (1LLU << b)))
541  bc++;
542  else
543  bc = 0;
544 
545  /* notify about complete message */
546  if ((GNUNET_NO == duplicate) &&
547  (0 == mc->bits))
548  {
549  GNUNET_STATISTICS_update(dc->stats,
550  _("# messages defragmented"),
551  1,
552  GNUNET_NO);
553  /* message complete, notify! */
554  dc->proc(dc->cls, mc->msg);
555  }
556  /* send ACK */
558  {
559  dc->latency = estimate_latency(mc);
560  }
561  delay = GNUNET_TIME_relative_saturating_multiply(dc->latency,
562  bc + 1);
563  if ((last + fid == num_fragments) ||
564  (0 == mc->bits) ||
565  (GNUNET_YES == duplicate))
566  {
567  /* message complete or duplicate or last missing fragment in
568  linear sequence; ACK now! */
569  delay = GNUNET_TIME_UNIT_ZERO;
570  }
571  if (NULL != mc->ack_task)
574  &send_ack,
575  mc);
576  if (GNUNET_YES == duplicate)
577  {
579  return GNUNET_NO;
580  }
581  return GNUNET_YES;
582 }
583 
584 /* 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:72
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:45
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:79
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.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t total_size
Total message size of the original message.
Definition: fragmentation.h:50
#define GNUNET_NO
Definition: gnunet_common.h:78
#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:67
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:181
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:1237
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.
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:76
uint16_t offset
Absolute offset (in bytes) of this fragment in the original message.
Definition: fragmentation.h:56
#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:63
Entry in list of pending tasks.
Definition: scheduler.c:131
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:77
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:956