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; }
/* 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; }