# define ASSERT_MASTER
#endif
+/*
+ * Make state transitions simpler.
+ */
+#define FINAL_STATE(_x) NO_CHILD_THREAD; request->component = "<" #_x ">"; request->module = ""; request->child_state = _x
+
+
static int event_new_fd(rad_listen_t *this);
/*
* and wait for the master thread timer to clean us up.
*/
if (!we_are_master()) {
- NO_CHILD_THREAD;
- request->child_state = REQUEST_DONE;
+ FINAL_STATE(REQUEST_DONE);
return;
}
#endif
if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
#endif
request->process = request_cleanup_delay;
- request->child_state = REQUEST_CLEANUP_DELAY;
+
+ if (!we_are_master()) {
+ FINAL_STATE(REQUEST_CLEANUP_DELAY);
+ return;
+ }
/*
* Update this if we can, otherwise let the timers pick it up.
*/
- if (we_are_master()) {
- STATE_MACHINE_TIMER(FR_ACTION_TIMER);
- } else {
- NO_CHILD_THREAD;
- }
+ request->child_state = REQUEST_CLEANUP_DELAY;
+#ifdef HAVE_PTHREAD_H
+ rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
+#endif
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
}
/*
* Enforce max_request_time.
*/
-static void request_max_time(REQUEST *request)
+static bool request_max_time(REQUEST *request)
{
struct timeval now, when;
rad_assert(request->magic == REQUEST_MAGIC);
if (request->child_state == REQUEST_DONE) {
done:
request_done(request, FR_ACTION_DONE);
- return;
+ return true;
}
/*
tv_add(&when, request->delay);
request->delay += request->delay >> 1;
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return false;
}
static void request_queue_or_run(REQUEST *request,
case FR_ACTION_TIMER:
fr_event_now(el, &now);
- rad_assert(request->response_delay.tv_sec > 0);
-
/*
* See if it's time to send the reply. If not,
* we wait some more.
*/
if (request->packet->dst_port == 0) {
RDEBUG("Finished internally proxied request.");
- NO_CHILD_THREAD;
- request->child_state = REQUEST_DONE;
+ FINAL_STATE(REQUEST_DONE);
return;
}
(request->root->reject_delay.tv_sec > 0)) {
request->response_delay = request->root->reject_delay;
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10) {
+ request->response_delay.tv_sec = vp->vp_integer;
+ } else {
+ request->response_delay.tv_sec = 10;
+ }
+ request->response_delay.tv_usec = 0;
+ } else {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY_USEC, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10 * USEC) {
+ request->response_delay.tv_sec = vp->vp_integer / USEC;
+ request->response_delay.tv_usec = vp->vp_integer % USEC;
+ } else {
+ request->response_delay.tv_sec = 10;
+ request->response_delay.tv_usec = 0;
+ }
+ }
+ }
+
#ifdef WITH_PROXY
/*
* If we timed out a proxy packet, don't delay
/*
* Send the reply.
*/
- if (request->response_delay.tv_sec == 0) {
- rad_assert(request->response_delay.tv_usec == 0);
+ if ((request->response_delay.tv_sec == 0) &&
+ (request->response_delay.tv_usec == 0)) {
/*
* Don't print a reply if there's none to send.
*/
if (request->reply->code != 0) {
+ if (rad_debug_lvl && request->state &&
+ (request->reply->code == PW_CODE_ACCESS_ACCEPT)) {
+ if (!fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY)) {
+ RWDEBUG2("Unused attributes found in &session-state:");
+ }
+ }
+
debug_packet(request, request->reply, false);
request->listener->send(request->listener, request);
}
done:
RDEBUG2("Finished request");
- request->component = "<core>";
- request->module = "<done>";
-
request_cleanup_delay_init(request);
} else {
RDEBUG2("Delaying response for %d.%06d seconds",
(int) request->response_delay.tv_sec, (int) request->response_delay.tv_usec);
request->listener->encode(request->listener, request);
- request->component = "<core>";
- request->module = "<delay>";
request->process = request_response_delay;
- NO_CHILD_THREAD;
- request->child_state = REQUEST_RESPONSE_DELAY;
+
+ FINAL_STATE(REQUEST_RESPONSE_DELAY);
}
}
switch (action) {
case FR_ACTION_TIMER:
COA_SEPARATE;
- request_max_time(request);
+ (void) request_max_time(request);
break;
case FR_ACTION_DUP:
child_state_names[request->child_state],
child_state_names[REQUEST_DONE]);
#endif
-
- NO_CHILD_THREAD;
- request->child_state = REQUEST_DONE;
+ FINAL_STATE(REQUEST_DONE);
break;
}
child_state_names[request->child_state],
child_state_names[REQUEST_RUNNING]);
#endif
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
request->handle = fun;
NO_CHILD_THREAD;
return 1;
}
+static void mark_home_server_alive(REQUEST *request, home_server_t *home)
+{
+ char buffer[128];
+
+ home->state = HOME_STATE_ALIVE;
+ home->response_timeouts = 0;
+ exec_trigger(request, home->cs, "home_server.alive", false);
+ home->currently_outstanding = 0;
+ home->num_sent_pings = 0;
+ home->num_received_pings = 0;
+ gettimeofday(&home->revive_time, NULL);
+
+ fr_event_delete(el, &home->ev);
+
+ RPROXY("Marking home server %s port %d alive",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+}
+
+
int request_proxy_reply(RADIUS_PACKET *packet)
{
RADIUS_PACKET **proxy_p;
#endif
/*
- * We've received a reply. If we hadn't been sending it
- * packets for a while, just mark it alive.
+ * If we hadn't been sending the home server packets for
+ * a while, just mark it alive. Or, if it was zombie,
+ * it's now responded, and is therefore alive.
*/
- if (request->home_server->state == HOME_STATE_UNKNOWN) {
- request->home_server->state = HOME_STATE_ALIVE;
- request->home_server->response_timeouts = 0;
+ if ((request->home_server->state == HOME_STATE_UNKNOWN) ||
+ (request->home_server->state == HOME_STATE_ZOMBIE)) {
+ mark_home_server_alive(request, request->home_server);
}
/*
break;
case FR_ACTION_TIMER:
- request_max_time(request);
+ (void) request_max_time(request);
break;
case FR_ACTION_PROXY_REPLY:
break;
case FR_ACTION_TIMER:
- request_max_time(request);
+ (void) request_max_time(request);
break;
case FR_ACTION_RUN:
/*
* Set the state function, then the state, no child, and
* send the packet.
+ *
+ * The order here is different from other state changes
+ * due to race conditions with replies from the home
+ * server.
*/
request->process = proxy_wait_for_reply;
request->child_state = REQUEST_PROXIED;
+ request->component = "<REQUEST_PROXIED>";
+ request->module = "";
NO_CHILD_THREAD;
/*
* Mark it alive and delete any outstanding
* pings.
*/
- home->state = HOME_STATE_ALIVE;
- home->response_timeouts = 0;
- exec_trigger(request, home->cs, "home_server.alive", false);
- home->currently_outstanding = 0;
- home->num_sent_pings = 0;
- home->num_received_pings = 0;
- gettimeofday(&home->revive_time, NULL);
-
- fr_event_delete(el, &home->ev);
-
- RPROXY("Marking home server %s port %d alive",
- inet_ntop(request->proxy->dst_ipaddr.af,
- &request->proxy->dst_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- request->proxy->dst_port);
+ mark_home_server_alive(request, home);
break;
default:
*/
start = now->tv_sec - ((home->zombie_period + 3) / 4);
if (home->last_packet_recv >= start) {
- DEBUG("Recieved reply from home server %d seconds ago. Might not be zombie.",
+ DEBUG("Received reply from home server %d seconds ago. Might not be zombie.",
(int) (now->tv_sec - home->last_packet_recv));
return;
}
ASSERT_MASTER;
CHECK_FOR_STOP;
+ if (request->parent) coa_separate(request);
+
switch (action) {
case FR_ACTION_TIMER:
- request_max_time(request);
-
- if (request->parent) coa_separate(request);
+ if (request_max_time(request)) break;
coa_retransmit(request);
break;
case FR_ACTION_PROXY_REPLY:
- if (request->parent) coa_separate(request);
-
request_queue_or_run(request, coa_running);
break;
switch (action) {
case FR_ACTION_TIMER:
- request_max_time(request);
+ (void) request_max_time(request);
break;
case FR_ACTION_PROXY_REPLY: /* too late! */
switch (action) {
case FR_ACTION_TIMER:
- request_max_time(request);
+ (void) request_max_time(request);
break;
case FR_ACTION_RUN: