/* 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 || e->packet_id < min_id) { min_id_defined = true; min_id = e->packet_id; } } } if (!min_id_defined || (int)(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; }
/* if we return BIG_TIMEOUT, nothing to wait for */ interval_t reliable_send_timeout (const struct reliable *rel) { struct gc_arena gc = gc_new (); interval_t ret = BIG_TIMEOUT; int i; const time_t local_now = now; for (i = 0; i < rel->size; ++i) { const struct reliable_entry *e = &rel->array[i]; if (e->active) { if (e->next_try <= local_now) { ret = 0; break; } else { ret = min_int (ret, e->next_try - local_now); } } } dmsg (D_REL_DEBUG, "ACK reliable_send_timeout %d %s", (int) ret, reliable_print_ids (rel, &gc)); gc_free (&gc); return ret; }
/* return true if reliable_send would return a non-NULL result */ bool reliable_can_send(const struct reliable *rel) { struct gc_arena gc = gc_new(); int i; int n_active = 0, n_current = 0; for (i = 0; i < rel->size; ++i) { const struct reliable_entry *e = &rel->array[i]; if (e->active) { ++n_active; if (now >= e->next_try) { ++n_current; } } } dmsg(D_REL_DEBUG, "ACK reliable_can_send active=%d current=%d : %s", n_active, n_current, reliable_print_ids(rel, &gc)); gc_free(&gc); return n_current > 0 && !rel->hold; }
/* true if at least one free buffer available */ bool reliable_can_get (const struct reliable *rel) { struct gc_arena gc = gc_new (); int i; for (i = 0; i < rel->size; ++i) { const struct reliable_entry *e = &rel->array[i]; if (!e->active) return true; } dmsg (D_REL_LOW, "ACK no free receive buffer available: %s", reliable_print_ids (rel, &gc)); gc_free (&gc); return false; }
/* make sure that incoming packet ID won't deadlock the receive buffer */ bool reliable_wont_break_sequentiality (const struct reliable *rel, packet_id_type id) { struct gc_arena gc = gc_new (); const int ret = reliable_pid_in_range2 (id, rel->packet_id, rel->size); if (!ret) { dmsg (D_REL_LOW, "ACK " packet_id_format " breaks sequentiality: %s", (packet_id_print_type)id, reliable_print_ids (rel, &gc)); } dmsg (D_REL_DEBUG, "ACK RWBS rel->size=%d rel->packet_id=%08x id=%08x ret=%d\n", rel->size, rel->packet_id, id, ret); gc_free (&gc); return ret; }
/* make sure that incoming packet ID won't deadlock the receive buffer */ bool reliable_wont_break_sequentiality (const struct reliable *rel, packet_id_type id) { struct gc_arena gc = gc_new (); int ret; if ((int)id < (int)rel->packet_id + rel->size) { ret = true; } else { dmsg (D_REL_LOW, "ACK " packet_id_format " breaks sequentiality: %s", (packet_id_print_type)id, reliable_print_ids (rel, &gc)); ret = false; } gc_free (&gc); return ret; }
/* 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 (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; }