GNUnet  0.20.0
Fragmentation library

Library to help fragment messages. More...

Collaboration diagram for Fragmentation library:

Typedefs

typedef void(* GNUNET_FRAGMENT_MessageProcessor) (void *cls, const struct GNUNET_MessageHeader *msg)
 Function that is called with messages created by the fragmentation module. More...
 
typedef 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. More...
 

Functions

struct GNUNET_FRAGMENT_ContextGNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, struct GNUNET_BANDWIDTH_Tracker *tracker, struct GNUNET_TIME_Relative msg_delay, struct GNUNET_TIME_Relative ack_delay, const struct GNUNET_MessageHeader *msg, GNUNET_FRAGMENT_MessageProcessor proc, void *proc_cls)
 Create a fragmentation context for the given message. More...
 
void GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc)
 Continuation to call from the 'proc' function after the fragment has been transmitted (and hence the next fragment can now be given to proc). More...
 
int GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, const struct GNUNET_MessageHeader *msg)
 Process an acknowledgement message we got from the other side (to control re-transmits). More...
 
void GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc, struct GNUNET_TIME_Relative *msg_delay, struct GNUNET_TIME_Relative *ack_delay)
 Destroy the given fragmentation context (stop calling 'proc', free resources). More...
 
const char * GNUNET_FRAGMENT_print_ack (const struct GNUNET_MessageHeader *ack)
 Convert an ACK message to a printable format suitable for logging. More...
 
struct GNUNET_DEFRAGMENT_ContextGNUNET_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. More...
 
void GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc)
 Destroy the given defragmentation context. More...
 
int GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, const struct GNUNET_MessageHeader *msg)
 We have received a fragment. More...
 

Detailed Description

Library to help fragment messages.

Todo:
Consider additional flow-control for sending from fragmentation based on continuations.

Typedef Documentation

◆ GNUNET_FRAGMENT_MessageProcessor

typedef void(* GNUNET_FRAGMENT_MessageProcessor) (void *cls, const struct GNUNET_MessageHeader *msg)

Function that is called with messages created by the fragmentation module.

In the case of the 'proc' callback of the GNUNET_FRAGMENT_context_create() function, this function must eventually call GNUNET_FRAGMENT_context_transmission_done().

Parameters
clsclosure
msgthe message that was created

Definition at line 68 of file gnunet_fragmentation_lib.h.

◆ GNUNET_DEFRAGMENT_AckProcessor

typedef 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.

Acknowledgements are cumulative, so it is OK to only transmit the 'latest' ack message for the same message ID.

Parameters
clsclosure
idunique message ID (modulo collisions)
msgthe message that was created

Definition at line 173 of file gnunet_fragmentation_lib.h.

Function Documentation

◆ GNUNET_FRAGMENT_context_create()

struct GNUNET_FRAGMENT_Context* GNUNET_FRAGMENT_context_create ( struct GNUNET_STATISTICS_Handle stats,
uint16_t  mtu,
struct GNUNET_BANDWIDTH_Tracker tracker,
struct GNUNET_TIME_Relative  msg_delay,
struct GNUNET_TIME_Relative  ack_delay,
const struct GNUNET_MessageHeader msg,
GNUNET_FRAGMENT_MessageProcessor  proc,
void *  proc_cls 
)

Create a fragmentation context for the given message.

Fragments the message into fragments of size mtu or less. Calls proc on each un-acknowledged fragment, using both the expected msg_delay between messages and acknowledgements and the given tracker to guide the frequency of calls to proc.

Parameters
statsstatistics context
mtuthe maximum message size for each fragment
trackerbandwidth tracker to use for flow control (can be NULL)
msg_delayinitial delay to insert between fragment transmissions based on previous messages
ack_delayexpected delay between fragment transmission and ACK based on previous messages
msgthe message to fragment
procfunction to call for each fragment to transmit
proc_clsclosure for proc
Returns
the fragmentation context

Fragments the message into fragments of size mtu or less. Calls proc on each un-acknowledged fragment, using both the expected msg_delay between messages and acknowledgements and the given tracker to guide the frequency of calls to proc.

Parameters
statsstatistics context
mtuthe maximum message size for each fragment
trackerbandwidth tracker to use for flow control (can be NULL)
msg_delayinitial delay to insert between fragment transmissions based on previous messages
ack_delayexpected delay between fragment transmission and ACK based on previous messages
msgthe message to fragment
procfunction to call for each fragment to transmit
proc_clsclosure for proc
Returns
the fragmentation context

Definition at line 310 of file fragmentation.c.

318 {
319  struct GNUNET_FRAGMENT_Context *fc;
320  size_t size;
321  uint64_t bits;
322 
324  _ ("# messages fragmented"),
325  1,
326  GNUNET_NO);
327  GNUNET_assert (mtu >= 1024 + sizeof(struct FragmentHeader));
328  size = ntohs (msg->size);
330  _ ("# total size of fragmented messages"),
331  size, GNUNET_NO);
332  GNUNET_assert (size >= sizeof(struct GNUNET_MessageHeader));
333  fc = GNUNET_malloc (sizeof(struct GNUNET_FRAGMENT_Context) + size);
334  fc->stats = stats;
335  fc->mtu = mtu;
336  fc->tracker = tracker;
337  fc->ack_delay = ack_delay;
338  fc->msg_delay = msg_delay;
339  fc->msg = (const struct GNUNET_MessageHeader *) &fc[1];
340  fc->proc = proc;
341  fc->proc_cls = proc_cls;
342  fc->fragment_id =
344  UINT32_MAX);
345  GNUNET_memcpy (&fc[1], msg, size);
346  bits =
347  (size + mtu - sizeof(struct FragmentHeader) - 1) / (mtu
348  - sizeof(struct
349  FragmentHeader));
350  GNUNET_assert (bits <= 64);
351  if (bits == 64)
352  fc->acks_mask = UINT64_MAX; /* set all 64 bit */
353  else
354  fc->acks_mask = (1LLU << bits) - 1; /* set lowest 'bits' bit */
355  fc->acks = fc->acks_mask;
357  return fc;
358 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static void transmit_next(void *cls)
Transmit the next fragment to the other peer.
struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_NO
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_malloc(size)
Wrapper around malloc.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1299
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 unsigned int size
Size of the "table".
Definition: peer.c:68
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Header for a message fragment.
Definition: fragmentation.h:39
Fragmentation context.
Definition: fragmentation.c:41
uint32_t fragment_id
Our fragmentation ID.
struct GNUNET_TIME_Relative ack_delay
Current expected delay for ACKs.
Definition: fragmentation.c:55
GNUNET_FRAGMENT_MessageProcessor proc
Function to call for transmissions.
Definition: fragmentation.c:80
struct GNUNET_TIME_Relative msg_delay
Current expected delay between messages.
Definition: fragmentation.c:60
struct GNUNET_SCHEDULER_Task * task
Task performing work for the fragmenter.
const struct GNUNET_MessageHeader * msg
Message to fragment (allocated at the end of this struct).
Definition: fragmentation.c:75
void * proc_cls
Closure for proc.
Definition: fragmentation.c:85
uint64_t acks_mask
Bitfield with all possible bits for acks (used to mask the ack we get back).
Definition: fragmentation.c:96
uint16_t mtu
Target fragment size.
uint64_t acks
Bitfield, set to 1 for each unacknowledged fragment.
Definition: fragmentation.c:90
struct GNUNET_STATISTICS_Handle * stats
Statistics to use.
Definition: fragmentation.c:45
struct GNUNET_BANDWIDTH_Tracker * tracker
Tracker for flow control.
Definition: fragmentation.c:50
Header for all communications.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.

References _, GNUNET_FRAGMENT_Context::ack_delay, GNUNET_FRAGMENT_Context::acks, GNUNET_FRAGMENT_Context::acks_mask, GNUNET_FRAGMENT_Context::fragment_id, GNUNET_assert, GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u32(), GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_SCHEDULER_add_now(), GNUNET_STATISTICS_update(), msg, GNUNET_FRAGMENT_Context::msg, GNUNET_FRAGMENT_Context::msg_delay, GNUNET_FRAGMENT_Context::mtu, GNUNET_FRAGMENT_Context::proc, GNUNET_FRAGMENT_Context::proc_cls, GNUNET_MessageHeader::size, size, stats, GNUNET_FRAGMENT_Context::stats, GNUNET_FRAGMENT_Context::task, GNUNET_FRAGMENT_Context::tracker, and transmit_next().

Referenced by handle_helper_message(), send_with_fragmentation(), and udp_plugin_send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_FRAGMENT_context_transmission_done()

void GNUNET_FRAGMENT_context_transmission_done ( struct GNUNET_FRAGMENT_Context fc)

Continuation to call from the 'proc' function after the fragment has been transmitted (and hence the next fragment can now be given to proc).

Parameters
fcfragmentation context

Definition at line 369 of file fragmentation.c.

370 {
372  fc->proc_busy = GNUNET_NO;
373  GNUNET_assert (fc->task == NULL);
374  fc->task =
376  &transmit_next,
377  fc);
378 }
@ GNUNET_YES
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at(struct GNUNET_TIME_Absolute at, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition: scheduler.c:1249
int8_t proc_busy
GNUNET_YES if we called proc and are now waiting for GNUNET_FRAGMENT_context_transmission_done()
struct GNUNET_TIME_Absolute delay_until
Next allowed transmission time.
Definition: fragmentation.c:65

References GNUNET_FRAGMENT_Context::delay_until, GNUNET_assert, GNUNET_NO, GNUNET_SCHEDULER_add_at(), GNUNET_YES, GNUNET_FRAGMENT_Context::proc_busy, GNUNET_FRAGMENT_Context::task, and transmit_next().

Referenced by fragment_transmission_done(), qc_fragment_sent(), and transmit_fragment().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_FRAGMENT_process_ack()

int GNUNET_FRAGMENT_process_ack ( struct GNUNET_FRAGMENT_Context fc,
const struct GNUNET_MessageHeader msg 
)

Process an acknowledgement message we got from the other side (to control re-transmits).

Parameters
fcfragmentation context
msgacknowledgement message we received
Returns
GNUNET_OK if this ack completes the work of the 'fc' (all fragments have been received); GNUNET_NO if more messages are pending GNUNET_SYSERR if this ack is not valid for this fc

Definition at line 393 of file fragmentation.c.

395 {
396  const struct FragmentAcknowledgement *fa;
397  uint64_t abits;
398  struct GNUNET_TIME_Relative ndelay;
399  unsigned int ack_cnt;
400  unsigned int snd_cnt;
401  unsigned int i;
402 
403  if (sizeof(struct FragmentAcknowledgement) != ntohs (msg->size))
404  {
405  GNUNET_break_op (0);
406  return GNUNET_SYSERR;
407  }
408  fa = (const struct FragmentAcknowledgement *) msg;
409  if (ntohl (fa->fragment_id) != fc->fragment_id)
410  return GNUNET_SYSERR; /* not our ACK */
411  abits = GNUNET_ntohll (fa->bits);
412  if ((GNUNET_YES == fc->wack) &&
413  (0 != fc->num_transmissions))
414  {
415  /* normal ACK, can update running average of delay... */
416  fc->wack = GNUNET_NO;
418  fc->ack_delay.rel_value_us =
419  (ndelay.rel_value_us / fc->num_transmissions + 3
420  * fc->ack_delay.rel_value_us) / 4;
421  /* calculate ratio msg sent vs. msg acked */
422  ack_cnt = 0;
423  snd_cnt = 0;
424  for (i = 0; i < 64; i++)
425  {
426  if (1 == (fc->acks_mask & (1ULL << i)))
427  {
428  snd_cnt++;
429  if (0 == (abits & (1ULL << i)))
430  ack_cnt++;
431  }
432  }
433  if (0 == ack_cnt)
434  {
435  /* complete loss */
437  snd_cnt);
438  }
439  else if (snd_cnt > ack_cnt)
440  {
441  /* some loss, slow down proportionally */
442  fc->msg_delay.rel_value_us = ((fc->msg_delay.rel_value_us * ack_cnt)
443  / snd_cnt);
444  }
445  else if (snd_cnt == ack_cnt)
446  {
447  fc->msg_delay.rel_value_us =
448  (ndelay.rel_value_us / fc->num_transmissions + 3
449  * fc->msg_delay.rel_value_us) / 5;
450  }
451  fc->num_transmissions = 0;
456  }
458  _ ("# fragment acknowledgements received"),
459  1,
460  GNUNET_NO);
461  if (abits != (fc->acks & abits))
462  {
463  /* ID collision or message reordering, count! This should be rare! */
465  _ ("# bits removed from fragmentation ACKs"), 1,
466  GNUNET_NO);
467  }
468  fc->acks = abits & fc->acks_mask;
469  if (0 != fc->acks)
470  {
471  /* more to transmit, do so right now (if tracker permits...) */
472  if (fc->task != NULL)
473  {
474  /* schedule next transmission now, no point in waiting... */
477  }
478  else
479  {
480  /* only case where there is no task should be if we're waiting
481  * for the right to transmit again (proc_busy set to YES) */
483  }
484  return GNUNET_NO;
485  }
486 
487  /* all done */
489  _ ("# fragmentation transmissions completed"),
490  1,
491  GNUNET_NO);
492  if (NULL != fc->task)
493  {
495  fc->task = NULL;
496  }
497  return GNUNET_OK;
498 }
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:54
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_TIME_Relative GNUNET_TIME_relative_min(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the minimum of two relative time values.
Definition: time.c:343
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:436
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:531
#define GNUNET_TIME_UNIT_SECONDS
One second.
Message fragment acknowledgement.
Definition: fragmentation.h:67
uint32_t fragment_id
Unique fragment ID.
Definition: fragmentation.h:76
uint64_t bits
Bits that are being acknowledged, in big-endian.
Definition: fragmentation.h:83
struct GNUNET_TIME_Absolute last_round
Time we transmitted the last message of the last round.
Definition: fragmentation.c:70
int8_t wack
GNUNET_YES if we are waiting for an ACK.
unsigned int num_transmissions
How many transmission have we completed in this round?
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.

References _, GNUNET_FRAGMENT_Context::ack_delay, GNUNET_FRAGMENT_Context::acks, GNUNET_FRAGMENT_Context::acks_mask, FragmentAcknowledgement::bits, GNUNET_FRAGMENT_Context::fragment_id, FragmentAcknowledgement::fragment_id, GNUNET_assert, GNUNET_break_op, GNUNET_NO, GNUNET_ntohll(), GNUNET_OK, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_SYSERR, GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_saturating_multiply(), GNUNET_TIME_UNIT_SECONDS, GNUNET_YES, GNUNET_FRAGMENT_Context::last_round, msg, GNUNET_FRAGMENT_Context::msg_delay, GNUNET_FRAGMENT_Context::num_transmissions, GNUNET_FRAGMENT_Context::proc_busy, GNUNET_TIME_Relative::rel_value_us, GNUNET_MessageHeader::size, GNUNET_FRAGMENT_Context::stats, GNUNET_FRAGMENT_Context::task, transmit_next(), and GNUNET_FRAGMENT_Context::wack.

Referenced by process_data(), and read_process_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_FRAGMENT_context_destroy()

void GNUNET_FRAGMENT_context_destroy ( struct GNUNET_FRAGMENT_Context fc,
struct GNUNET_TIME_Relative msg_delay,
struct GNUNET_TIME_Relative ack_delay 
)

Destroy the given fragmentation context (stop calling 'proc', free resources).

Parameters
fcfragmentation context
msg_delaywhere to store average delay between individual message transmissions the last message (OUT only)
ack_delaywhere to store average delay between transmission and ACK for the last message, set to FOREVER if the message was not fully transmitted (OUT only)

Definition at line 512 of file fragmentation.c.

515 {
516  if (fc->task != NULL)
518  if (NULL != ack_delay)
519  *ack_delay = fc->ack_delay;
520  if (NULL != msg_delay)
522  fc->num_rounds);
523  GNUNET_free (fc);
524 }
#define GNUNET_free(ptr)
Wrapper around free.
unsigned int num_rounds
How many rounds of transmission have we completed so far?

References GNUNET_FRAGMENT_Context::ack_delay, GNUNET_free, GNUNET_SCHEDULER_cancel(), GNUNET_TIME_relative_saturating_multiply(), GNUNET_FRAGMENT_Context::msg_delay, GNUNET_FRAGMENT_Context::num_rounds, and GNUNET_FRAGMENT_Context::task.

Referenced by fragmented_message_done(), free_fragment_message(), and free_session().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_FRAGMENT_print_ack()

const char* GNUNET_FRAGMENT_print_ack ( const struct GNUNET_MessageHeader ack)

Convert an ACK message to a printable format suitable for logging.

Parameters
ackmessage to print
Returns
ack in human-readable format

Definition at line 147 of file fragmentation.c.

148 {
149  static char buf[128];
150  const struct FragmentAcknowledgement *fa;
151 
152  if (sizeof(struct FragmentAcknowledgement) !=
153  htons (ack->size))
154  return "<malformed ack>";
155  fa = (const struct FragmentAcknowledgement *) ack;
157  sizeof(buf),
158  "%u-%llX",
159  ntohl (fa->fragment_id),
160  (unsigned long long) GNUNET_ntohll (fa->bits));
161  return buf;
162 }
static char buf[2048]
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.

References FragmentAcknowledgement::bits, buf, FragmentAcknowledgement::fragment_id, GNUNET_ntohll(), GNUNET_snprintf(), and GNUNET_MessageHeader::size.

Referenced by read_process_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_DEFRAGMENT_context_create()

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.

Parameters
statsstatistics context
mtuthe maximum message size for each fragment
num_msgshow many fragmented messages to we defragment at most at the same time?
clsclosure for proc and ackp
procfunction to call with defragmented messages
ackpfunction to call with acknowledgements (to send back to the other side)
Returns
the defragmentation context

Definition at line 208 of file defragmentation.c.

213 {
215 
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 }
static struct GNUNET_FS_DownloadContext * dc
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Defragmentation context (one per connection).
uint16_t mtu
Maximum message size for each fragment.
GNUNET_DEFRAGMENT_AckProcessor ackp
Function to call with acknowledgements.
GNUNET_FRAGMENT_MessageProcessor proc
Function to call with defragmented messages.
unsigned int num_msgs
num_msgs how many fragmented messages to we defragment at most at the same time?
void * cls
Closure for proc and ackp.

References GNUNET_DEFRAGMENT_Context::ackp, GNUNET_DEFRAGMENT_Context::cls, dc, GNUNET_new, GNUNET_TIME_UNIT_SECONDS, GNUNET_DEFRAGMENT_Context::mtu, GNUNET_DEFRAGMENT_Context::num_msgs, GNUNET_DEFRAGMENT_Context::proc, and stats.

Referenced by create_macendpoint(), and read_process_fragment().

Here is the caller graph for this function:

◆ GNUNET_DEFRAGMENT_context_destroy()

void GNUNET_DEFRAGMENT_context_destroy ( struct GNUNET_DEFRAGMENT_Context dc)

Destroy the given defragmentation context.

Parameters
dcdefragmentation context

Definition at line 234 of file defragmentation.c.

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 }
static struct GNUNET_TESTBED_Controller * mc
Handle to the master controller.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
Information we keep for one message that is being assembled.

References dc, GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_SCHEDULER_cancel(), and mc.

Referenced by ack_proc(), free_macendpoint(), heap_cleanup_iterator(), read_process_fragment(), and udp_disconnect_session().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_DEFRAGMENT_process_fragment()

int GNUNET_DEFRAGMENT_process_fragment ( struct GNUNET_DEFRAGMENT_Context dc,
const struct GNUNET_MessageHeader msg 
)

We have received a fragment.

Process it.

Parameters
dcthe context
msgthe message that was received
Returns
GNUNET_OK on success, GNUNET_NO if this was a duplicate, GNUNET_SYSERR on error

Definition at line 416 of file defragmentation.c.

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;
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  }
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)
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;
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  {
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  }
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! */
575  }
576  if (NULL != mc->ack_task)
577  GNUNET_SCHEDULER_cancel (mc->ack_task);
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 }
static void discard_oldest_mc(struct GNUNET_DEFRAGMENT_Context *dc)
Discard the message context that was inactive for the longest time.
static void send_ack(void *cls)
Send acknowledgement to the other peer now.
static struct GNUNET_TIME_Relative estimate_latency(struct MessageContext *mc)
Estimate the latency between messages based on the most recent message time stamps.
static struct GNUNET_TIME_Relative delay
When should dkg communication start?
static struct GNUNET_DISK_FileHandle * fh
File handle to STDIN, for reading restart/quit commands.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of 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:1272
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
Time for absolute times used by GNUnet, in microseconds.

Referenced by process_data(), and read_process_fragment().

Here is the caller graph for this function: