void
reliable_mark_active_incoming (struct reliable *rel, struct buffer *buf,
			       packet_id_type pid, int opcode)
{
  int i;
  for (i = 0; i < rel->size; ++i)
    {
      struct reliable_entry *e = &rel->array[i];
      if (buf == &e->buf)
	{
	  e->active = true;

	  /* packets may not arrive in sequential order */
	  e->packet_id = pid;

	  /* check for replay */
	  ASSERT (!reliable_pid_min (pid, rel->packet_id));

	  e->opcode = opcode;
	  e->next_try = 0;
	  e->timeout = 0;
	  dmsg (D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id);
	  return;
	}
    }
  ASSERT (0);			/* buf not found in rel */
}
/* grab a free buffer, fail if buffer clogged by unacknowledged low packet IDs */
struct buffer *
reliable_get_buf_output_sequenced (struct reliable *rel)
{
  struct gc_arena gc = gc_new ();
  int i;
  packet_id_type min_id = 0;
  bool min_id_defined = false;
  struct buffer *ret = NULL;

  /* find minimum active packet_id */
  for (i = 0; i < rel->size; ++i)
    {
      const struct reliable_entry *e = &rel->array[i];
      if (e->active)
	{
	  if (!min_id_defined || reliable_pid_min (e->packet_id, min_id))
	    {
	      min_id_defined = true;
	      min_id = e->packet_id;
	    }
	}
    }

  if (!min_id_defined || reliable_pid_in_range1 (rel->packet_id, min_id, rel->size))
    {
      ret = reliable_get_buf (rel);
    }
  else
    {
      dmsg (D_REL_LOW, "ACK output sequence broken: %s", reliable_print_ids (rel, &gc));
    }
  gc_free (&gc);
  return ret;
}
/* return next buffer to send to remote */
struct buffer *
reliable_send (struct reliable *rel, int *opcode)
{
  int i;
  struct reliable_entry *best = NULL;
  const time_t local_now = now;

  for (i = 0; i < rel->size; ++i)
    {
      struct reliable_entry *e = &rel->array[i];
      if (e->active && local_now >= e->next_try)
	{
	  if (!best || reliable_pid_min (e->packet_id, best->packet_id))
	    best = e;
	}
    }
  if (best)
    {
#ifdef EXPONENTIAL_BACKOFF
      /* exponential backoff */
      best->next_try = reliable_unique_retry (rel, local_now + best->timeout);
      best->timeout *= 2;
#else
      /* constant timeout, no backoff */
      best->next_try = local_now + best->timeout;
#endif
      *opcode = best->opcode;
      dmsg (D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)",
	   (packet_id_print_type)best->packet_id, best->buf.len,
	   (int)(best->next_try - local_now));
      return &best->buf;
    }
  return NULL;
}
Exemple #4
0
/* make sure that incoming packet ID isn't a replay */
bool
reliable_not_replay(const struct reliable *rel, packet_id_type id)
{
    struct gc_arena gc = gc_new();
    int i;
    if (reliable_pid_min(id, rel->packet_id))
    {
        goto bad;
    }
    for (i = 0; i < rel->size; ++i)
    {
        const struct reliable_entry *e = &rel->array[i];
        if (e->active && e->packet_id == id)
        {
            goto bad;
        }
    }
    gc_free(&gc);
    return true;

bad:
    dmsg(D_REL_DEBUG, "ACK " packet_id_format " is a replay: %s", (packet_id_print_type)id, reliable_print_ids(rel, &gc));
    gc_free(&gc);
    return false;
}