rlm_radius_udp_connection_t *c; //!< The connection state machine.
rlm_radius_link_t *link; //!< More link stuff.
rlm_radius_request_t *rr; //!< ID tracking, resend count, etc.
+
+ rlm_radius_retransmit_t timer; //!< retransmission data structures
+
uint8_t *packet; //!< Packet we write to the network.
size_t packet_len; //!< Length of the packet.
};
/*
* Stop all retransmissions for this packet.
*/
- if (u->rr->ev) (void) fr_event_timer_delete(c->thread->el, &u->rr->ev);
+ if (u->timer.ev) (void) fr_event_timer_delete(c->thread->el, &u->timer.ev);
switch (c->state) {
default:
/*
* Track the Most Recently Started with reply
*/
- if (timercmp(&rr->start, &c->mrs_time, >)) {
- c->mrs_time = rr->start;
+ if (timercmp(&u->timer.start, &c->mrs_time, >)) {
+ c->mrs_time = u->timer.start;
}
(void) fr_heap_insert(c->thread->active, c);
uint32_t delay;
struct timeval diff;
- fr_timeval_subtract(&diff, now, &u->rr->start);
+ fr_timeval_subtract(&diff, now, &u->timer.start);
delay = u->initial_delay_time + diff.tv_sec;
delay = htonl(delay);
memcpy(u->acct_delay_time, &delay, 4);
}
}
- RDEBUG("Retransmitting request. Expecting response within %d.%06ds",
- u->rr->rt / USEC, u->rr->rt % USEC);
+ RDEBUG("Retransmitting request (%d/%d). Expecting response within %d.%06ds",
+ u->timer.count, c->inst->parent->retry[u->code].mrc, u->timer.rt / USEC, u->timer.rt % USEC);
/*
* Debug the packet again, including any extra
* Start the retransmission timers.
*/
u->link->time_sent = fr_time();
- fr_time_to_timeval(&u->rr->start, u->link->time_sent);
+ fr_time_to_timeval(&u->timer.start, u->link->time_sent);
if (proxy_state) {
c->num_requests++;
if (!c->inst->parent->synchronous) {
RDEBUG("Proxying request. Expecting response within %d.%06ds",
- u->rr->rt / USEC, u->rr->rt % USEC);
+ u->timer.rt / USEC, u->timer.rt % USEC);
if (rr_track_start(c->id, u->rr, c->thread->el, response_timeout, u,
&c->inst->parent->retry[u->code]) < 0) {
RDEBUG("Proxying request. Relying on NAS to perform retransmissions");
}
- } else if (u->rr->count == 0) {
+ } else if (u->timer.count == 0) {
if (rr_track_start(c->id, u->rr, c->thread->el, status_check_timeout,
u, &c->inst->parent->retry[u->code]) < 0) {
RDEBUG("Failed starting retransmit tracking");
RDEBUG("Sending %s status check. Expecting response within %d.%06ds",
fr_packet_codes[u->code],
- u->rr->rt / USEC, u->rr->rt % USEC);
+ u->timer.rt / USEC, u->timer.rt % USEC);
} else {
RDEBUG("Retransmitting %s status check. Expecting response within %d.%06ds",
fr_packet_codes[u->code],
- u->rr->rt / USEC, u->rr->rt % USEC);
+ u->timer.rt / USEC, u->timer.rt % USEC);
}
fr_dlist_remove(&u->entry);
*
* @param[in] fd of connection that failed.
* @param[in] state the connection was in when it failed.
- * @param[in] uctx the connection.
+ * @param[in] uctx the connection.
*/
static fr_connection_state_t _conn_failed(int fd, fr_connection_state_t state, void *uctx)
{
* demand. If the proxied packets use all of the
* IDs, then we can't send a Status-Server check.
*/
- u->rr = rr_track_alloc(c->id, request, u->code, link);
+ u->rr = rr_track_alloc(c->id, request, u->code, link, &u->timer);
if (!u->rr) {
ERROR("%s - Failed allocating status_check ID for new connection %s",
c->inst->parent->name, c->name);
*/
u->rr = NULL;
u->c = NULL;
- (void) fr_event_timer_delete(c->thread->el, &u->rr->ev);
+ (void) fr_event_timer_delete(c->thread->el, &u->timer.ev);
fr_dlist_remove(&u->entry);
(void) fr_heap_insert(t->queued, u);
t->pending = true;
rad_assert(c->state == CONN_ACTIVE);
rad_assert(c->num_requests < c->max_requests);
- u->rr = rr_track_alloc(c->id, u->link->request, u->code, u->link);
+ u->rr = rr_track_alloc(c->id, u->link->request, u->code, u->link, &u->timer);
if (!u->rr) {
rad_assert(0 == 1);
return NULL;
}
- rad_assert(u->rr->count == 0);
+ rad_assert(u->timer.count == 0);
u->c = c;
fr_heap_extract(t->active, c);
* The timers are parented from the request, so
* we have to manually free them here.
*/
- talloc_const_free(id->id[i].ev);
+ talloc_const_free(id->id[i].timer->ev);
}
return 0;
* - NULL on error
* - rlm_radius_request_t on success
*/
-rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link)
+rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link,
+ rlm_radius_retransmit_t *timer)
{
fr_dlist_t *entry;
rlm_radius_request_t *rr;
done:
rr->link = link;
rr->request = request;
- rr->ev = NULL;
+
+ rr->timer = timer;
+ rr->timer->ev = NULL;
rr->code = code;
/* rr->id is already allocated */
- rr->start.tv_sec = 0;
- rr->start.tv_usec = 0;
- rr->count = 0;
- rr->rt = 0;
+ rr->timer->start.tv_sec = 0;
+ rr->timer->start.tv_usec = 0;
+ rr->timer->count = 0;
+ rr->timer->rt = 0;
id->num_requests++;
return rr;
(void) talloc_get_type_abort(id, rlm_radius_id_t);
rr->request = NULL;
- if (rr->ev) {
- talloc_const_free(rr->ev);
- rr->ev = NULL;
+ if (rr->timer->ev) {
+ talloc_const_free(rr->timer->ev);
+ rr->timer->ev = NULL;
}
rad_assert(id->num_requests > 0);
* Get when we SHOULD have woken up, which might not be
* the same as 'now'.
*/
- next = rr->start;
- next.tv_usec += rr->rt;
+ next = rr->timer->start;
+ next.tv_usec += rr->timer->rt;
/*
* Increment retransmission counter
*/
- rr->count++;
+ rr->timer->count++;
/*
* We retried too many times. Fail.
*/
- if (retry->mrc && (rr->count > retry->mrc)) {
+ if (retry->mrc && (rr->timer->count > retry->mrc)) {
DEBUG3("RETRANSMIT - reached MRC %d", retry->mrc);
return 0;
}
if (retry->mrd) {
struct timeval end;
- end = rr->start;
+ end = rr->timer->start;
end.tv_sec += retry->mrd;
if (timercmp(now, &end, >=)) {
delay = fr_rand();
delay ^= (delay >> 16);
delay &= 0xffff;
- frac = rr->rt / 5;
+ frac = rr->timer->rt / 5;
delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
- delay += (2 * rr->rt) - (rr->rt / 10);
+ delay += (2 * rr->timer->rt) - (rr->timer->rt / 10);
/*
* Cap delay at MRT
/*
* And finally set the retransmission timer.
*/
- rr->rt = delay;
+ rr->timer->rt = delay;
/*
* Get the next delay time.
*/
- next.tv_usec += rr->rt;
+ next.tv_usec += rr->timer->rt;
next.tv_sec += (next.tv_usec / USEC);
next.tv_usec %= USEC;
- if (fr_event_timer_insert(id, el, &rr->ev, &next, callback, uctx) < 0) {
+ if (fr_event_timer_insert(id, el, &rr->timer->ev, &next, callback, uctx) < 0) {
return -1;
}
- DEBUG3("RETRANSMIT - in %d.%06ds", rr->rt / USEC, rr->rt % USEC);
+ DEBUG3("RETRANSMIT - in %d.%06ds", rr->timer->rt / USEC, rr->timer->rt % USEC);
return 1;
}
{
struct timeval next;
- rr->count = 1;
- rr->rt = retry->irt * USEC; /* rt is in usec */
+ rr->timer->count = 1;
+ rr->timer->rt = retry->irt * USEC; /* rt is in usec */
- next = rr->start;
- next.tv_usec += rr->rt;
+ next = rr->timer->start;
+ next.tv_usec += rr->timer->rt;
next.tv_sec += (next.tv_usec / USEC);
next.tv_usec %= USEC;
- if (fr_event_timer_insert(id, el, &rr->ev, &next, callback, uctx) < 0) {
+ if (fr_event_timer_insert(id, el, &rr->timer->ev, &next, callback, uctx) < 0) {
return -1;
}
* @copyright 2017 Alan DeKok <aland@freeradius.org>
*/
+typedef struct rlm_radius_retransmit_t {
+ struct timeval start; //!< when we started sending the packet
+ uint32_t count; //!< how many times we sent this packet
+ uint32_t rt; //!< retransmit timer (microseconds)
+ fr_event_timer_t const *ev; //!< timer event associated with this packet
+} rlm_radius_retransmit_t;
+
/** Track one request to a response
*
*/
rlm_radius_link_t *link; //!< to the rlm_radius thread context, and to the IO submodule
REQUEST *request; //!< as always...
- fr_event_timer_t const *ev; //!< timer event associated with this packet
-
int code; //!< packet code (sigh)
int id; //!< our ID
- struct timeval start; //!< when we started sending the packet
- uint32_t count; //!< how many times we sent this packet
- uint32_t rt; //!< retransmit timer (microseconds)
+
+ rlm_radius_retransmit_t *timer; //!< retransmission
union {
fr_dlist_t entry; //!< for free chain
} rlm_radius_id_t;
rlm_radius_id_t *rr_track_create(TALLOC_CTX *ctx);
-rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link) CC_HINT(nonnull);
+rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code,
+ rlm_radius_link_t *link, rlm_radius_retransmit_t *timer) CC_HINT(nonnull);
int rr_track_update(rlm_radius_id_t *id, rlm_radius_request_t *rr, uint8_t *vector) CC_HINT(nonnull);
rlm_radius_request_t *rr_track_find(rlm_radius_id_t *id, int packet_id, uint8_t *vector) CC_HINT(nonnull(1));
int rr_track_delete(rlm_radius_id_t *id, rlm_radius_request_t *rr) CC_HINT(nonnull);