};
#ifdef DEBUG_STATE_MACHINE
-#define TRACE_STATE_MACHINE if (debug_flag) printf("(%u) ********\tSTATE %s action %s live M-%s C-%s\t********\n", request->number, __FUNCTION__, action_codes[action], master_state_names[request->master_state], child_state_names[request->child_state])
+#define TRACE_STATE_MACHINE if (debug_flag) do { struct timeval debug_tv; \
+ gettimeofday(&debug_tv, NULL);\
+ debug_tv.tv_sec -= fr_start_time;\
+ printf("(%u) %d.%06d ********\tSTATE %s action %s live M-%s C-%s\t********\n",\
+ request->number, (int) debug_tv.tv_sec, (int) debug_tv.tv_usec, __FUNCTION__, action_codes[action], master_state_names[request->master_state], child_state_names[request->child_state]); } while (0)
static char const *master_state_names[REQUEST_MASTER_NUM_STATES] = {
"?",
fr_event_insert(el, request_timer, request, \
&when, &request->ev);
-
+/*
+ * We need a different VERIFY_REQUEST macro in process.c
+ * To avoid the race conditions with the master thread
+ * checking the REQUEST whilst it's being worked on by
+ * the child.
+ */
+#if defined(WITH_VERIFY_PTR) && defined(HAVE_PTHREAD_H)
+# undef VERIFY_REQUEST
+# define VERIFY_REQUEST(_x) if (pthread_equal(pthread_self(), _x->child_pid) != 0) verify_request(__FILE__, __LINE__, _x)
+#endif
/**
* @section request_timeline
#ifdef HAVE_PTHREAD_H
#ifdef WITH_PROXY
-static pthread_mutex_t proxy_mutex;
-static rad_listen_t *proxy_listener_list = NULL;
+static pthread_mutex_t proxy_mutex;
static bool proxy_no_new_sockets = false;
#endif
#define NO_CHILD_THREAD
#endif
+#if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
+static bool we_are_master(void)
+{
+ if (spawn_flag &&
+ (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
+ return false;
+ }
+
+ return true;
+}
+#define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
+
+#else
+#define we_are_master(_x) (1)
+#define ASSERT_MASTER
+#endif
+
+static int event_new_fd(rad_listen_t *this);
+
/*
* We need mutexes around the event FD list *only* in certain
* cases.
*/
#if defined (HAVE_PTHREAD_H) && (defined(WITH_PROXY) || defined(WITH_TCP))
+static rad_listen_t *new_listeners = NULL;
+
static pthread_mutex_t fd_mutex;
#define FD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
#define FD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
+
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * Just do it ourselves.
+ */
+ if (we_are_master()) {
+ event_new_fd(this);
+ return;
+ }
+
+ FD_MUTEX_LOCK(&fd_mutex);
+
+ /*
+ * If it's already in the list, don't add it again.
+ */
+ if (this->next) {
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ return;
+ }
+
+ /*
+ * Otherwise, add it to the list
+ */
+ this->next = new_listeners;
+ new_listeners = this;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
+}
#else
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * No threads. Just insert it.
+ */
+ event_new_fd(this);
+}
/*
* This is easier than ifdef's throughout the code.
*/
#define FD_MUTEX_UNLOCK(_x)
#endif
-static int request_num_counter = 0;
+static int request_num_counter = 1;
#ifdef WITH_PROXY
static int request_will_proxy(REQUEST *request);
static int request_proxy(REQUEST *request, int retransmit);
STATE_MACHINE_DECL(proxy_wait_for_reply);
STATE_MACHINE_DECL(proxy_no_reply);
STATE_MACHINE_DECL(proxy_running);
-static int process_proxy_reply(REQUEST *request);
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply);
static void remove_from_proxy_hash(REQUEST *request);
static void remove_from_proxy_hash_nl(REQUEST *request, bool yank);
static int insert_into_proxy_hash(REQUEST *request);
RADCLIENT *client, RAD_REQUEST_FUNP fun);
STATE_MACHINE_DECL(request_common);
-
-#if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
-static bool we_are_master(void)
-{
- if (spawn_flag &&
- (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
- return false;
- }
-
- return true;
-}
-#define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
-
-#else
-#define we_are_master(_x) (1)
-#define ASSERT_MASTER
-#endif
-
STATE_MACHINE_DECL(request_response_delay);
STATE_MACHINE_DECL(request_cleanup_delay);
STATE_MACHINE_DECL(request_running);
static void request_coa_originate(REQUEST *request);
STATE_MACHINE_DECL(coa_running);
STATE_MACHINE_DECL(coa_wait_for_reply);
+STATE_MACHINE_DECL(coa_no_reply);
static void request_coa_separate(REQUEST *coa);
#endif
}
/*
- * In daemon mode, AND this request has debug flags set.
+ * Debug the packet if requested.
*/
-#define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
+#define DEBUG_PACKET if (request->log.lvl && request->log.func) debug_packet
static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
{
char buffer[1024];
char const *received, *from;
fr_ipaddr_t const *ip;
- int port;
+ uint16_t port;
if (!packet) return;
- rad_assert(request->radlog != NULL);
+ rad_assert(request->log.func != NULL);
if (direction == 0) {
received = "Received";
*
***********************************************************************/
+static struct timeval *request_response_window(REQUEST *request)
+{
+ VERIFY_REQUEST(request);
+
+ if (request->client) {
+ /*
+ * The client hasn't set the response window. Return
+ * either the home server one, if set, or the global one.
+ */
+ if (!timerisset(&request->client->response_window)) {
+ return &request->home_server->response_window;
+ }
+
+ if (timercmp(&request->client->response_window,
+ &request->home_server->response_window, <)) {
+ return &request->client->response_window;
+ }
+ }
+
+ rad_assert(request->home_server != NULL);
+ return &request->home_server->response_window;
+}
+
+/*
+ * Determine initial request processing delay.
+ */
+static int request_init_delay(REQUEST *request)
+{
+ struct timeval half_response_window;
+
+ VERIFY_REQUEST(request);
+
+ /* Allow client response window to lower initial delay */
+ if (timerisset(&request->client->response_window)) {
+ half_response_window.tv_sec = request->client->response_window.tv_sec >> 1;
+ half_response_window.tv_usec =
+ ((request->client->response_window.tv_sec & 1) * USEC +
+ request->client->response_window.tv_usec) >> 1;
+ if (timercmp(&half_response_window, &request->root->init_delay, <))
+ return (int)half_response_window.tv_sec * USEC +
+ (int)half_response_window.tv_usec;
+ }
+
+ return (int)request->root->init_delay.tv_sec * USEC +
+ (int)request->root->init_delay.tv_usec;
+}
+
/*
* Callback for ALL timer events related to the request.
*/
static void request_timer(void *ctx)
{
- REQUEST *request = ctx;
- int action = request->timer_action;
+ REQUEST *request = talloc_get_type_abort(ctx, REQUEST);
+ int action;
+
+ action = request->timer_action;
TRACE_STATE_MACHINE;
char buffer[128];
#endif
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
#ifdef WITH_COA
request->listener->send(request->listener, request);
return;
} else {
- RDEBUG("No reply. Ignoring retransmit.");
+ RDEBUG("No reply. Ignoring retransmit");
}
break;
* packets from the home server.
*/
case FR_ACTION_PROXY_REPLY:
- DEBUG2("Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
+ RDEBUG2("Reply from home server %s port %d - ID: %d arrived too late. Try increasing 'retry_delay' or 'max_request_time'",
inet_ntop(request->proxy->src_ipaddr.af,
&request->proxy->src_ipaddr.ipaddr,
buffer, sizeof(buffer)),
- request->proxy->dst_port, request->proxy->id,
- request->number);
+ request->proxy->dst_port, request->proxy->id);
return;
#endif
when.tv_sec += request->home_server->coa_mrd;
} else
#endif
- when.tv_sec += request->home_server->response_window;
+ timeradd(&when, request_response_window(request), &when);
/*
* We haven't received all responses, AND there's still
if (request->ev) fr_event_delete(el, &request->ev);
- request_free(&request);
+ talloc_free(request);
}
{
struct timeval now, when;
+ VERIFY_REQUEST(request);
+
if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) goto done;
if (!request->root->cleanup_delay) goto done;
int action = FR_ACTION_TIMER;
#endif
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
ASSERT_MASTER;
if (request->listener->status != RAD_LISTEN_STATUS_KNOWN) {
if ((request->master_state == REQUEST_ACTIVE) &&
(request->child_state < REQUEST_RESPONSE_DELAY)) {
- WDEBUG("Socket was closed while processing request %u: Stopping it.", request->number);
+ WARN("Socket was closed while processing request %u: Stopping it.", request->number);
request->master_state = REQUEST_STOP_PROCESSING;
}
}
switch (request->child_state) {
case REQUEST_QUEUED:
case REQUEST_RUNNING:
-#ifdef WITH_PROXY
- case REQUEST_PROXIED:
-#endif
when = request->packet->timestamp;
when.tv_sec += request->root->max_request_time;
#endif
request->master_state = REQUEST_STOP_PROCESSING;
}
+ goto delay; /* sleep some more */
#ifdef WITH_PROXY
+ case REQUEST_PROXIED:
+ when = request->packet->timestamp;
+ when.tv_sec += request->root->max_request_time;
+
+ if (timercmp(&now, &when, >=)) {
+ RWDEBUG("No response to proxied request in 'max_request_time'. Stopping it.");
+ request->master_state = REQUEST_STOP_PROCESSING;
+ request_done(request, FR_ACTION_DONE);
+ break;
+ }
+
+ rad_assert(request->proxy != NULL);
+#ifdef WITH_COA
/*
- * We should wait for the proxy reply.
+ * Ugh.
*/
- if (request->child_state == REQUEST_PROXIED) {
+ if (request->packet->code != request->proxy->code) {
if (request->proxy_reply) {
- request->process = proxy_running;
+ request->process = coa_running;
} else {
- request->process = proxy_wait_for_reply;
+ request->process = coa_wait_for_reply;
}
- }
+ } else
#endif
+ if (request->proxy_reply) {
+ request->process = proxy_running;
+ } else {
+ request->process = proxy_wait_for_reply;
+ }
+
+ when = request->proxy->timestamp;
+ tv_add(&when, request->delay);
+
+ if (timercmp(&now, &when, >=)) {
+ request->process(request, FR_ACTION_TIMER);
+ return;
+ }
+
/*
- * If the request has been told to die, we wait.
- * Otherwise, we wait for the child thread to
- * finish it's work.
+ * Leave the initial delay alone.
*/
- goto delay;
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+#endif /* WITH_PROXY */
case REQUEST_RESPONSE_DELAY:
rad_assert(request->response_delay > 0);
int action = FR_ACTION_TIMER;
#endif
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
/*
/*
* (re) set the initial delay.
*/
- request->delay = USEC / 3;
+ request->delay = request_init_delay(request);
+ if (request->delay > USEC) request->delay = USEC;
gettimeofday(&when, NULL);
tv_add(&when, request->delay);
request->delay += request->delay >> 1;
char buffer[128];
#endif
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
ASSERT_MASTER;
* We're still waiting for a proxy reply.
*/
if (request->child_state == REQUEST_PROXIED) {
+ request->process = proxy_wait_for_reply;
proxy_wait_for_reply(request, action);
return;
}
#endif
- /*
- * We probbly should check if the request is
- * DONE. If so, delete it, and allow the new
- * request to continue. But we can't give
- * feedback to request_receive(), so we let it
- * take care of that.
- */
- ERROR("(%u) Discarding duplicate request from "
- "client %s port %d - ID: %u due to unfinished request",
- request->number, request->client->shortname,
- request->packet->src_port,request->packet->id);
+ ERROR("(%u) Ignoring duplicate packet from "
+ "client %s port %d - ID: %u due to unfinished request "
+ "in component %s module %s",
+ request->number, request->client->shortname,
+ request->packet->src_port,request->packet->id,
+ request->component, request->module);
break;
case FR_ACTION_CONFLICTING:
#ifdef WITH_PROXY
case FR_ACTION_PROXY_REPLY:
- DEBUG2("Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
- inet_ntop(request->proxy->src_ipaddr.af,
- &request->proxy->src_ipaddr.ipaddr,
+ RDEBUG2("Reply from home server %s port %d - ID: %d arrived too late. Try increasing 'retry_delay' or 'max_request_time'",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
- request->proxy->dst_port, request->proxy->id,
- request->number);
+ request->proxy->dst_port, request->proxy->id);
return;
#endif
{
struct timeval when;
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
ASSERT_MASTER;
if (request->reply->code != 0) {
request->listener->send(request->listener, request);
} else {
- RDEBUG("No reply. Ignoring retransmit.");
+ RDEBUG("No reply. Ignoring retransmit");
}
/*
STATE_MACHINE_DECL(request_response_delay)
{
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
ASSERT_MASTER;
}
-static int request_pre_handler(REQUEST *request, UNUSED int action)
+static int CC_HINT(nonnull) request_pre_handler(REQUEST *request, UNUSED int action)
{
- TRACE_STATE_MACHINE;
-
int rcode;
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+
if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
/*
return 1;
}
-#ifdef WITH_PROXY
- /*
- * Put the decoded packet into it's proper place.
- */
- if (request->proxy_reply != NULL) {
- /*
- * There may be a proxy reply, but it may be too late.
- */
- if (!request->proxy_listener) return 0;
-
- rcode = request->proxy_listener->decode(request->proxy_listener, request);
- DEBUG_PACKET(request, request->proxy_reply, 0);
-
- /*
- * Pro-actively remove it from the proxy hash.
- * This is later than in 2.1.x, but it means that
- * the replies are authenticated before being
- * removed from the hash.
- */
- if ((rcode == 0) &&
- (request->num_proxied_requests <= request->num_proxied_responses)) {
- remove_from_proxy_hash(request);
- }
-
- } else
-#endif
- if (request->packet->vps == NULL) {
+ if (!request->packet->vps) { /* FIXME: check for correct state */
rcode = request->listener->decode(request->listener, request);
#ifdef WITH_UNLANG
* Ignore parse errors.
*/
if (radius_evaluate_cond(request, RLM_MODULE_OK, 0, debug_condition)) {
- request->options = 2;
- request->radlog = vradlog_request;
+ request->log.lvl = L_DBG_LVL_2;
+ request->log.func = vradlog_request;
}
}
#endif
}
if (!request->username) {
- rad_assert(request->packet != NULL);
request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
}
-#ifdef WITH_PROXY
- if (action == FR_ACTION_PROXY_REPLY) {
- return process_proxy_reply(request);
- }
-#endif
-
return 1;
}
{
VALUE_PAIR *vp;
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
(void) action; /* -Wunused */
/*
* Catch Auth-Type := Reject BEFORE proxying the packet.
*/
- else if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
+ else if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
if (request->reply->code == 0) {
vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
- if (!vp || (vp->vp_integer != PW_CODE_AUTHENTICATION_REJECT)) {
+ if (!vp || (vp->vp_integer != PW_CODE_ACCESS_REJECT)) {
RDEBUG2("There was no response configured: "
"rejecting request");
}
- request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_ACCESS_REJECT;
}
}
if (vp) pairadd(&request->reply->vps, vp);
switch (request->reply->code) {
- case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_ACCEPT:
rad_postauth(request);
break;
case PW_CODE_ACCESS_CHALLENGE:
* We do this separately so ACK and challenge can change the code
* to reject if a module returns reject.
*/
- if (request->reply->code == PW_CODE_AUTHENTICATION_REJECT) {
+ if (request->reply->code == PW_CODE_ACCESS_REJECT) {
pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
if (vp) rad_postauth(request);
/*
* See if we need to delay an Access-Reject packet.
*/
- if ((request->reply->code == PW_CODE_AUTHENTICATION_REJECT) &&
+ if ((request->reply->code == PW_CODE_ACCESS_REJECT) &&
(request->root->reject_delay > 0)) {
request->response_delay = request->root->reject_delay;
+
+#ifdef WITH_PROXY
+ /*
+ * If we timed out a proxy packet, don't delay
+ * the reject any more.
+ */
+ if (request->proxy && !request->proxy_reply) {
+ request->response_delay = 0;
+ }
+#endif
+
}
/*
STATE_MACHINE_DECL(request_running)
{
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
switch (action) {
case FR_ACTION_PROXY_REPLY:
request->child_state = REQUEST_RUNNING;
request->process = proxy_running;
- /* FALL-THROUGH */
+ request->process(request, FR_ACTION_RUN);
+ break;
#endif
case FR_ACTION_RUN:
int request_receive(rad_listen_t *listener, RADIUS_PACKET *packet,
RADCLIENT *client, RAD_REQUEST_FUNP fun)
{
- int count;
+ uint32_t count;
RADIUS_PACKET **packet_p;
REQUEST *request = NULL;
struct timeval now;
listen_socket_t *sock = NULL;
+ VERIFY_PACKET(packet);
+
/*
* Set the last packet received.
*/
#ifdef WITH_STATS
switch (packet->code) {
- case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_ACCESS_REQUEST:
FR_STATS_INC(auth, total_dup_requests);
break;
/*
* Quench maximum number of outstanding requests.
*/
- if (mainconfig.max_requests &&
- ((count = fr_packet_list_num_elements(pl)) > mainconfig.max_requests)) {
- static time_t last_complained = 0;
-
- if (last_complained == now.tv_sec) return 0;
-
- last_complained = now.tv_sec;
-
- ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
- client->shortname,
- packet->src_port, packet->id);
- WARN("Please check the configuration file.\n"
- "\tThe value for 'max_requests' is probably set too low.\n");
+ if (main_config.max_requests &&
+ ((count = fr_packet_list_num_elements(pl)) > main_config.max_requests)) {
+ RATE_LIMIT(ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
+ client->shortname,
+ packet->src_port, packet->id);
+ WARN("Please check the configuration file.\n"
+ "\tThe value for 'max_requests' is probably set too low.\n"));
exec_trigger(NULL, NULL, "server.max_requests", true);
return 0;
* Rate-limit the incoming packets
*/
if (sock && sock->max_rate) {
- int pps;
-
- pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now,
- &sock->rate_time, &now);
+ uint32_t pps;
+ pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now, &sock->rate_time, &now);
if (pps > sock->max_rate) {
DEBUG("Dropping request due to rate limiting");
return 0;
} else {
RDEBUG("Not sending reply");
}
- request_free(&request);
+ talloc_free(request);
return 1;
}
request->reply = rad_alloc(request, 0);
if (!request->reply) {
ERROR("No memory");
- request_free(&request);
+ talloc_free(request);
return NULL;
}
#ifdef WITH_STATS
request->listener->stats.last_packet = request->packet->timestamp.tv_sec;
- if (packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
+ if (packet->code == PW_CODE_ACCESS_REQUEST) {
request->client->auth.last_packet = request->packet->timestamp.tv_sec;
radius_auth_stats.last_packet = request->packet->timestamp.tv_sec;
#ifdef WITH_ACCOUNTING
request->server = NULL;
}
- request->root = &mainconfig;
+ request->root = &main_config;
#ifdef WITH_TCP
request->listener->count++;
#endif
*/
static void tcp_socket_timer(void *ctx)
{
- rad_listen_t *listener = ctx;
+ rad_listen_t *listener = talloc_get_type_abort(ctx, rad_listen_t);
listen_socket_t *sock = listener->data;
struct timeval end, now;
char buffer[256];
fr_socket_limit_t *limit;
+ ASSERT_MASTER;
+
fr_event_now(el, &now);
if (listener->status != RAD_LISTEN_STATUS_KNOWN) return;
*/
static int eol_proxy_listener(void *ctx, void *data)
{
- rad_listen_t *this = ctx;
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
RADIUS_PACKET **proxy_p = data;
REQUEST *request;
static int eol_listener(void *ctx, void *data)
{
- rad_listen_t *this = ctx;
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
RADIUS_PACKET **packet_p = data;
REQUEST *request;
*/
static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
{
+ VERIFY_REQUEST(request);
+
if (!request->in_proxy_hash) return;
fr_packet_list_id_free(proxy_list, request->proxy, yank);
static void remove_from_proxy_hash(REQUEST *request)
{
+ VERIFY_REQUEST(request);
+
/*
* Check this without grabbing the mutex because it's a
* lot faster that way.
int rcode, tries;
void *proxy_listener;
+ VERIFY_REQUEST(request);
+
rad_assert(request->proxy != NULL);
rad_assert(request->home_server != NULL);
rad_assert(proxy_list != NULL);
for (tries = 0; tries < 2; tries++) {
rad_listen_t *this;
+ listen_socket_t *sock;
RDEBUG3("proxy: Trying to allocate ID (%d/2)", tries);
rcode = fr_packet_list_id_alloc(proxy_list,
request->proxy->src_port = 0; /* Use any new socket */
proxy_listener = this;
+ sock = this->data;
+ if (!fr_packet_list_socket_add(proxy_list, this->fd,
+ sock->proto,
+ &sock->other_ipaddr, sock->other_port,
+ this)) {
+
+#ifdef HAVE_PTHREAD_H
+ proxy_no_new_sockets = true;
+#endif
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ /*
+ * This is bad. However, the
+ * packet list now supports 256
+ * open sockets, which should
+ * minimize this problem.
+ */
+ ERROR("Failed adding proxy socket: %s",
+ fr_strerror());
+ goto fail;
+ }
+
/*
- * Add it to the event loop (and to the packet list)
- * before we try to grab another Id.
+ * Add it to the event loop. Ensure that we have
+ * only one mutex locked at a time.
*/
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
- if (!event_new_fd(this)) {
- RDEBUG3("proxy: Failed inserting new socket into event loop");
- listen_free(&this);
- goto fail;
- }
+ radius_update_listener(this);
PTHREAD_MUTEX_LOCK(&proxy_mutex);
}
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
- RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
+ RDEBUG3("proxy: allocating destination %s port %d - Id %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
request->proxy->dst_port,
return 1;
}
-static int process_proxy_reply(REQUEST *request)
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply)
{
int rcode;
int post_proxy_type = 0;
VALUE_PAIR *vp;
+ VERIFY_REQUEST(request);
+
+ /*
+ * There may be a proxy reply, but it may be too late.
+ */
+ if (!request->proxy_listener) return 0;
+
/*
* Delete any reply we had accumulated until now.
*/
* If we have a proxy_reply, and it was a reject, setup
* post-proxy-type Reject
*/
- if (!vp && request->proxy_reply &&
- request->proxy_reply->code == PW_CODE_AUTHENTICATION_REJECT) {
+ if (!vp && reply &&
+ reply->code == PW_CODE_ACCESS_REJECT) {
DICT_VALUE *dval;
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Reject");
if (vp) {
post_proxy_type = vp->vp_integer;
- RDEBUG2(" Found Post-Proxy-Type %s",
- dict_valnamebyattr(PW_POST_PROXY_TYPE, 0,
- post_proxy_type));
+ RDEBUG2("Found Post-Proxy-Type %s", dict_valnamebyattr(PW_POST_PROXY_TYPE, 0, post_proxy_type));
+ }
+
+ if (reply) {
+ VERIFY_PACKET(reply);
+ /*
+ * Decode the packet.
+ */
+ rcode = request->proxy_listener->decode(request->proxy_listener, request);
+ DEBUG_PACKET(request, reply, 0);
+
+ /*
+ * Pro-actively remove it from the proxy hash.
+ * This is later than in 2.1.x, but it means that
+ * the replies are authenticated before being
+ * removed from the hash.
+ */
+ if ((rcode == 0) &&
+ (request->num_proxied_requests <= request->num_proxied_responses)) {
+ remove_from_proxy_hash(request);
+ }
+ } else {
+ remove_from_proxy_hash(request);
}
if (request->home_pool && request->home_pool->virtual_server) {
char const *old_server = request->server;
request->server = request->home_pool->virtual_server;
- RDEBUG2(" server %s {", request->server);
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
rcode = process_post_proxy(post_proxy_type, request);
- RDEBUG2(" }");
+ REXDENT();
+ RDEBUG2("}");
request->server = old_server;
} else {
rcode = process_post_proxy(post_proxy_type, request);
* There may NOT be a proxy reply, as we may be
* running Post-Proxy-Type = Fail.
*/
- if (request->proxy_reply) {
+ if (reply) {
+ pairadd(&request->reply->vps, paircopy(request->reply, reply->vps));
+
/*
* Delete the Proxy-State Attributes from
* the reply. These include Proxy-State
* attributes from us and remote server.
*/
- pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
-
- /*
- * Add the attributes left in the proxy
- * reply to the reply list.
- */
- pairfilter(request->reply, &request->reply->vps,
- &request->proxy_reply->vps, 0, 0, TAG_ANY);
-
- /*
- * Free proxy request pairs.
- */
- pairfree(&request->proxy->vps);
+ pairdelete(&request->reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
}
switch (rcode) {
struct timeval now;
char buffer[128];
+ VERIFY_PACKET(packet);
+
PTHREAD_MUTEX_LOCK(&proxy_mutex);
proxy_p = fr_packet_list_find_byreply(proxy_list, packet);
* Call the state machine to do something useful with the
* request.
*/
- request->proxy_reply = packet;
+ request->proxy_reply = talloc_steal(request, packet);
packet->timestamp = now;
request->priority = RAD_LISTEN_PROXY;
*/
if (request->home_server->state == HOME_STATE_UNKNOWN) {
request->home_server->state = HOME_STATE_ALIVE;
+ request->home_server->response_timeouts = 0;
}
#ifdef WITH_STATS
request->home_server->stats.last_packet = packet->timestamp.tv_sec;
request->proxy_listener->stats.last_packet = packet->timestamp.tv_sec;
- if (request->proxy->code == PW_CODE_AUTHENTICATION_REQUEST) {
+ if (request->proxy->code == PW_CODE_ACCESS_REQUEST) {
proxy_auth_stats.last_packet = packet->timestamp.tv_sec;
#ifdef WITH_ACCOUNTING
} else if (request->proxy->code == PW_CODE_ACCOUNTING_REQUEST) {
DICT_VALUE const *dval = NULL;
VALUE_PAIR *vp;
- if (request->proxy->code == PW_CODE_AUTHENTICATION_REQUEST) {
+ VERIFY_REQUEST(request);
+
+ if (request->proxy->code == PW_CODE_ACCESS_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
"Fail-Authentication");
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect");
#endif
} else {
- WDEBUG("Unknown packet type in Post-Proxy-Type Fail: ignoring");
+ WARN("Unknown packet type in Post-Proxy-Type Fail: ignoring");
return 0;
}
STATE_MACHINE_DECL(proxy_no_reply)
{
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
switch (action) {
break;
case FR_ACTION_RUN:
- /*
- * Which will take care of calling post-proxy-type fail.
- */
- request_running(request, FR_ACTION_PROXY_REPLY);
+ if (process_proxy_reply(request, NULL)) {
+ request_finish(request, action);
+ }
+ request_done(request, FR_ACTION_DONE);
break;
default:
STATE_MACHINE_DECL(proxy_running)
{
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
switch (action) {
break;
case FR_ACTION_RUN:
- request_running(request, action);
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ request_finish(request, action);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
break;
default:
REALM *realm = NULL;
home_pool_t *pool = NULL;
+ VERIFY_REQUEST(request);
+
if (!request->root->proxy_requests) return 0;
if (request->packet->dst_port == 0) return 0;
if (request->packet->code == PW_CODE_STATUS_SERVER) return 0;
/*
* Figure out which pool to use.
*/
- if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
pool = realm->auth_pool;
#ifdef WITH_ACCOUNTING
if (!vp) return 0;
switch (request->packet->code) {
- case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_ACCESS_REQUEST:
pool_type = HOME_TYPE_AUTH;
break;
* since we can't use the request authenticator
* anymore - we changed it.
*/
- if ((request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) &&
+ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
pairfind(request->proxy->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
pairfind(request->proxy->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
vp = radius_paircreate(request->proxy, &request->proxy->vps, PW_CHAP_CHALLENGE, 0);
DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
/* Must be a validation issue */
rad_assert(dval);
- RDEBUG2(" Found Pre-Proxy-Type %s", dval->name);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
pre_proxy_type = vp->vp_integer;
}
char const *old_server = request->server;
request->server = request->home_pool->virtual_server;
- RDEBUG2(" server %s {", request->server);
+
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
rcode = process_pre_proxy(pre_proxy_type, request);
- RDEBUG2(" }");
- request->server = old_server;
+ REXDENT();
+ RDEBUG2("}");
+
+ request->server = old_server;
} else {
rcode = process_pre_proxy(pre_proxy_type, request);
}
{
char buffer[128];
+ VERIFY_REQUEST(request);
+
rad_assert(request->parent == NULL);
rad_assert(request->home_server != NULL);
REQUEST *fake;
if (request->packet->dst_port == 0) {
- WDEBUG("Cannot proxy an internal request.");
+ WARN("Cannot proxy an internal request");
return 0;
}
request->proxy_reply = talloc_steal(request, fake->reply);
fake->reply = NULL;
- request_free(&fake);
+ talloc_free(fake);
/*
* Just do the work here, rather than trying to
* run the "decode proxy reply" stuff...
*/
- process_proxy_reply(request);
+ process_proxy_reply(request, request->proxy_reply);
request->handle(request); /* to do more post-proxy stuff */
* We're actually sending a proxied packet. Do that now.
*/
if (!request->in_proxy_hash && !insert_into_proxy_hash(request)) {
- EDEBUG("Failed to insert request into the proxy list.");
+ ERROR("Failed to insert request into the proxy list");
return -1;
}
rad_assert(request->proxy->id >= 0);
+ if (debug_flag) {
+ struct timeval *response_window;
+
+ response_window = request_response_window(request);
+
#ifdef WITH_TLS
- if (request->home_server->tls) {
- RDEBUG2("Proxying request to home server %s port %d (TLS)",
- inet_ntop(request->proxy->dst_ipaddr.af,
- &request->proxy->dst_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- request->proxy->dst_port);
- } else
+ if (request->home_server->tls) {
+ RDEBUG2("Proxying request to home server %s port %d (TLS) timeout %d.%06d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ (int) response_window->tv_sec, (int) response_window->tv_usec);
+ } else
#endif
- RDEBUG2("Proxying request to home server %s port %d",
- inet_ntop(request->proxy->dst_ipaddr.af,
- &request->proxy->dst_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- request->proxy->dst_port);
+ RDEBUG2("Proxying request to home server %s port %d timeout %d.%06d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ (int) response_window->tv_sec, (int) response_window->tv_usec);
- DEBUG_PACKET(request, request->proxy, 1);
+ DEBUG_PACKET(request, request->proxy, 1);
+ }
gettimeofday(&request->proxy_retransmit, NULL);
if (!retransmit) {
{
home_server_t *home;
+ VERIFY_REQUEST(request);
+
/*
* Delete the request from the proxy list.
*
home_server_update_request(home, request);
if (!insert_into_proxy_hash(request)) {
- RPROXY("Failed to insert retransmission into the proxy list.");
+ RPROXY("Failed to insert retransmission into the proxy list");
goto post_proxy_fail;
}
home_server_t *home = request->home_server;
char buffer[128];
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
ASSERT_MASTER;
* 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;
*/
static void ping_home_server(void *ctx)
{
- home_server_t *home = ctx;
+ home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
REQUEST *request;
VALUE_PAIR *vp;
struct timeval when, now;
"Message-Authenticator", "0x00", T_OP_SET);
} else if (home->type == HOME_TYPE_AUTH) {
- request->proxy->code = PW_CODE_AUTHENTICATION_REQUEST;
+ request->proxy->code = PW_CODE_ACCESS_REQUEST;
pairmake(request->proxy, &request->proxy->vps,
"User-Name", home->ping_user_name, T_OP_SET);
rad_assert(!request->in_request_hash);
rad_assert(!request->in_proxy_hash);
rad_assert(request->ev == NULL);
- request_free(&request);
+ talloc_free(request);
return;
}
exec_trigger(&my_request, home->cs, trigger, false);
}
-static void mark_home_server_zombie(home_server_t *home, struct timeval *now)
+static void mark_home_server_zombie(home_server_t *home, struct timeval *now, struct timeval *response_window)
{
time_t start;
char buffer[128];
#ifdef WITH_TCP
if (home->proto == IPPROTO_TCP) {
- WDEBUG("Not marking TCP server %s zombie", home->name);
+ WARN("Not marking TCP server %s zombie", home->name);
return;
}
#endif
home->num_sent_pings = 0;
home->num_received_pings = 0;
- PROXY( "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
+ PROXY( "Marking home server %s port %d as zombie (it has not responded in %d.%06d seconds).",
inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
buffer, sizeof(buffer)),
- home->port, home->response_window);
+ home->port, (int) response_window->tv_sec, (int) response_window->tv_usec);
ping_home_server(home);
}
void revive_home_server(void *ctx)
{
- home_server_t *home = ctx;
+ home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
char buffer[128];
#ifdef WITH_TCP
#endif
home->state = HOME_STATE_ALIVE;
+ home->response_timeouts = 0;
home_trigger(home, "home_server.alive");
home->currently_outstanding = 0;
gettimeofday(&home->revive_time, NULL);
#ifdef WITH_TCP
if (home->proto == IPPROTO_TCP) {
- WDEBUG("Not marking TCP server dead");
+ WARN("Not marking TCP server dead");
return;
}
#endif
STATE_MACHINE_DECL(proxy_wait_for_reply)
{
struct timeval now, when;
+ struct timeval *response_window = NULL;
home_server_t *home = request->home_server;
char buffer[128];
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
rad_assert(request->packet->code != PW_CODE_STATUS_SERVER);
break;
case FR_ACTION_TIMER:
+ response_window = request_response_window(request);
+
#ifdef WITH_TCP
if (!request->proxy_listener ||
(request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
* responding to other (better looking) packets.
*/
when = request->proxy->timestamp;
- when.tv_sec += home->response_window;
+ timeradd(&when, response_window, &when);
/*
* Not at the response window. Set the timer for
* that.
*/
if (timercmp(&when, &now, >)) {
- RDEBUG("Expecting proxy response no later than %d seconds from now", home->response_window);
+ struct timeval diff;
+ timersub(&when, &now, &diff);
+
+ RDEBUG("Expecting proxy response no later than %d.%06d seconds from now",
+ (int) diff.tv_sec, (int) diff.tv_usec);
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
}
&& (home->proto != IPPROTO_TCP)
#endif
) {
- mark_home_server_zombie(home, &now);
+ home->response_timeouts++;
+ if (home->response_timeouts >= home->max_response_timeouts)
+ mark_home_server_zombie(home, &now, response_window);
}
FR_STATS_TYPE_INC(home->stats.total_timeouts);
* may have failed over to another home server.
* But that one may be dead, too.
*/
- RERROR("Failing request - proxy ID %u, due to lack of any response from home server %s port %d",
- request->proxy->id,
+ RERROR("Failing proxied request, due to lack of any response from home server %s port %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
request->proxy->dst_port);
- if (!setup_post_proxy_fail(request)) {
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, proxy_no_reply);
+ } else {
gettimeofday(&request->reply->timestamp, NULL);
request_cleanup_delay_init(request, NULL);
- return;
}
-
- /*
- * Remember that we didn't have a reply.
- */
- request_queue_or_run(request, proxy_no_reply);
break;
/*
fr_ipaddr_t ipaddr;
char buffer[256];
- rad_assert(request != NULL);
+ VERIFY_REQUEST(request);
+
rad_assert(request->coa != NULL);
rad_assert(request->proxy == NULL);
rad_assert(!request->in_proxy_hash);
if (vp) {
if (vp->vp_integer == 0) {
fail:
- request_free(&request->coa);
+ TALLOC_FREE(request->coa);
return;
}
}
home_server_update_request(coa->home_server, coa);
} else if (!coa->home_server) {
- int port = PW_COA_UDP_PORT;
+ uint16_t port = PW_COA_UDP_PORT;
vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
if (vp) port = vp->vp_integer;
DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
/* Must be a validation issue */
rad_assert(dval);
- RDEBUG2(" Found Pre-Proxy-Type %s", dval->name);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
pre_proxy_type = vp->vp_integer;
}
char const *old_server = coa->server;
coa->server = coa->home_pool->virtual_server;
- RDEBUG2(" server %s {", coa->server);
+ RDEBUG2("server %s {", coa->server);
+ RINDENT();
rcode = process_pre_proxy(pre_proxy_type, coa);
- RDEBUG2(" }");
+ REXDENT();
+ RDEBUG2("}");
coa->server = old_server;
} else {
rcode = process_pre_proxy(pre_proxy_type, coa);
coa->proxy->dst_port = coa->home_server->port;
if (!insert_into_proxy_hash(coa)) {
- radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list.");
+ radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list");
goto fail;
}
static void coa_timer(REQUEST *request)
{
- int delay, frac;
+ uint32_t delay, frac;
struct timeval now, when, mrd;
+ VERIFY_REQUEST(request);
+
rad_assert(request->parent == NULL);
if (request->proxy_reply) return request_process_timer(request);
&request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
request->proxy->dst_port);
- if (!setup_post_proxy_fail(request)) {
+
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, coa_no_reply);
+ } else {
request_done(request, FR_ACTION_DONE);
- return;
}
-
- request_queue_or_run(request, coa_running);
return;
}
{
rad_assert(request->parent == NULL);
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
switch (action) {
case FR_ACTION_PROXY_REPLY:
rad_assert(request->parent == NULL);
-#ifdef HAVE_PTHREAD_H
- /*
- * Catch the case of a proxy reply when called
- * from the main worker thread.
- */
- if (we_are_master()) {
- request_queue_or_run(request, coa_running);
- return;
- }
- /* FALL-THROUGH */
-#endif
- case FR_ACTION_RUN:
- request_running(request, action);
+ request_queue_or_run(request, coa_running);
break;
default:
#ifdef DEBUG_STATE_MACHINE
int action = FR_ACTION_TIMER;
#endif
+
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
rad_assert(request->parent != NULL);
request->process(request, FR_ACTION_TIMER);
}
+STATE_MACHINE_DECL(coa_no_reply)
+{
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ request_common(request, action);
+ break;
+
+ case FR_ACTION_PROXY_REPLY: /* too late! */
+ RDEBUG2("Reply from CoA server %s port %d - ID: %d arrived too late.",
+ inet_ntop(request->proxy->src_ipaddr.af,
+ &request->proxy->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port, request->proxy->id);
+ break;
+
+ case FR_ACTION_RUN:
+ /*
+ * FIXME: do recv_coa Fail
+ */
+ (void) process_proxy_reply(request, NULL);
+ request_done(request, FR_ACTION_DONE);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
STATE_MACHINE_DECL(coa_running)
{
+ VERIFY_REQUEST(request);
+
TRACE_STATE_MACHINE;
switch (action) {
break;
case FR_ACTION_RUN:
- request_running(request, FR_ACTION_PROXY_REPLY);
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ request_finish(request, action);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
break;
default:
***********************************************************************/
static void event_socket_handler(UNUSED fr_event_list_t *xel, UNUSED int fd, void *ctx)
{
- rad_listen_t *listener = ctx;
+ rad_listen_t *listener = talloc_get_type_abort(ctx, rad_listen_t);
rad_assert(xel == el);
}
#ifdef WITH_DETAIL
+#ifdef WITH_DETAIL_THREAD
+#else
/*
* This function is called periodically to see if this detail
* file is available for reading.
static void event_poll_detail(void *ctx)
{
int delay;
- rad_listen_t *this = ctx;
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
struct timeval when, now;
listen_detail_t *detail = this->data;
fr_exit(1);
}
}
-#endif
+#endif /* WITH_DETAIL_THREAD */
+#endif /* WITH_DETAIL */
static void event_status(struct timeval *wake)
{
if (debug_flag == 0) {
if (just_started) {
- INFO("Ready to process requests.");
+ INFO("Ready to process requests");
just_started = false;
}
return;
}
if (!wake) {
- INFO("Ready to process requests.");
+ INFO("Ready to process requests");
} else if ((wake->tv_sec != 0) ||
(wake->tv_usec >= 100000)) {
#ifdef WITH_TCP
static void listener_free_cb(void *ctx)
{
- rad_listen_t *this = ctx;
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
char buffer[1024];
if (this->count > 0) {
}
#endif
-int event_new_fd(rad_listen_t *this)
+static int event_new_fd(rad_listen_t *this)
{
char buffer[1024];
+ ASSERT_MASTER;
+
if (this->status == RAD_LISTEN_STATUS_KNOWN) return 1;
this->print(this, buffer, sizeof(buffer));
INFO(" ... adding new socket %s", buffer);
}
-#ifdef WITH_PROXY
- /*
- * Add it to the list of sockets we can use.
- * Server sockets (i.e. auth/acct) are never
- * added to the packet list.
- */
- if (this->type == RAD_LISTEN_PROXY) {
- PTHREAD_MUTEX_LOCK(&proxy_mutex);
- if (!fr_packet_list_socket_add(proxy_list, this->fd,
- sock->proto,
- &sock->other_ipaddr, sock->other_port,
- this)) {
-
-#ifdef HAVE_PTHREAD_H
- proxy_no_new_sockets = true;
-#endif
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
-
- /*
- * This is bad. However, the
- * packet list now supports 256
- * open sockets, which should
- * minimize this problem.
- */
- ERROR("Failed adding proxy socket: %s",
- fr_strerror());
- return 0;
- }
-
- if (sock->home) {
- sock->home->limit.num_connections++;
-
-#ifdef HAVE_PTHREAD_H
- /*
- * If necessary, add it to the list of
- * new proxy listeners.
- */
- if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
- this->next = proxy_listener_list;
- proxy_listener_list = this;
- }
-#endif
- }
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
-
- /*
- * Tell the main thread that we've added
- * a proxy listener, but only if we need
- * to update the event list. Do this
- * with the mutex unlocked, to reduce
- * contention.
- */
- if (sock->home) {
- if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
- radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
- }
- }
- }
-#endif
-
+ switch (this->type) {
#ifdef WITH_DETAIL
/*
* Detail files are always known, and aren't
* put into the socket event loop.
*/
- if (this->type == RAD_LISTEN_DETAIL) {
+ case RAD_LISTEN_DETAIL:
this->status = RAD_LISTEN_STATUS_KNOWN;
+#ifndef WITH_DETAIL_THREAD
/*
* Set up the first poll interval.
*/
event_poll_detail(this);
return 1;
- }
+#else
+ break; /* add the FD to the list */
#endif
+#endif /* WITH_DETAIL */
-#ifdef WITH_TCP
+#ifdef WITH_PROXY
/*
- * Add timers to child sockets, if necessary.
+ * Add it to the list of sockets we can use.
+ * Server sockets (i.e. auth/acct) are never
+ * added to the packet list.
*/
- if (sock->proto == IPPROTO_TCP && sock->opened &&
- (sock->limit.lifetime || sock->limit.idle_timeout)) {
- struct timeval when;
+ case RAD_LISTEN_PROXY:
+#ifdef WITH_TCP
+ /*
+ * Add timers to outgoing child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->home->limit.lifetime || sock->home->limit.idle_timeout)) {
+ struct timeval when;
- ASSERT_MASTER;
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
- when.tv_sec = sock->opened + 1;
- when.tv_usec = 0;
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
+ }
+#endif
+ break;
+#endif /* WITH_PROXY */
- if (!fr_event_insert(el, tcp_socket_timer, this, &when,
- &(sock->ev))) {
- rad_panic("Failed to insert event");
+ /*
+ * FIXME: put idle timers on command sockets.
+ */
+
+ default:
+#ifdef WITH_TCP
+ /*
+ * Add timers to incoming child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->limit.lifetime || sock->limit.idle_timeout)) {
+ struct timeval when;
+
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
}
- }
#endif
+ break;
+ } /* switch over listener types */
- FD_MUTEX_LOCK(&fd_mutex);
+ /*
+ * All sockets: add the FD to the event handler.
+ */
if (!fr_event_fd_insert(el, 0, this->fd,
event_socket_handler, this)) {
ERROR("Failed adding event handler for socket!");
fr_exit(1);
}
- FD_MUTEX_UNLOCK(&fd_mutex);
this->status = RAD_LISTEN_STATUS_KNOWN;
return 1;
/*
* Remove it from the list of live FD's.
*/
- FD_MUTEX_LOCK(&fd_mutex);
fr_event_fd_delete(el, 0, this->fd);
- FD_MUTEX_UNLOCK(&fd_mutex);
#ifdef WITH_PROXY
/*
buffer, fr_strerror());
fr_exit(1);
}
- if (sock->home && sock->home->limit.num_connections) {
- sock->home->limit.num_connections--;
- }
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
} else
#endif
static void handle_signal_self(int flag)
{
+ ASSERT_MASTER;
+
if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
INFO("Signalled to exit");
return;
}
- INFO("Received HUP signal.");
+ INFO("Received HUP signal");
last_hup = when;
}
#ifdef WITH_DETAIL
+#ifndef WITH_DETAIL_THREAD
if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
rad_listen_t *this;
/*
* FIXME: O(N) loops suck.
*/
- for (this = mainconfig.listen;
+ for (this = main_config.listen;
this != NULL;
this = this->next) {
if (this->type != RAD_LISTEN_DETAIL) continue;
}
}
#endif
+#endif
#ifdef WITH_TCP
#ifdef WITH_PROXY
#ifdef HAVE_PTHREAD_H
/*
- * Add event handlers for idle timeouts && maximum lifetime.
+ * There are new listeners in the list. Run
+ * event_new_fd() on them.
*/
if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
- struct timeval when, now;
-
- fr_event_now(el, &now);
-
- PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ rad_listen_t *this, *next;
- while (proxy_listener_list) {
- rad_listen_t *this = proxy_listener_list;
- listen_socket_t *sock = this->data;
+ FD_MUTEX_LOCK(&fd_mutex);
- rad_assert(sock->proto == IPPROTO_TCP);
- proxy_listener_list = this->next;
+ /*
+ * FIXME: unlock the mutex before calling
+ * event_new_fd()?
+ */
+ for (this = new_listeners; this != NULL; this = next) {
+ next = this->next;
this->next = NULL;
- if (!sock->home) continue; /* skip UDP sockets */
-
- when = now;
-
- /*
- * Sockets should only be added to the
- * proxy_listener_list if they have limits.
- *
- */
- rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
-
- if (!fr_event_insert(el, tcp_socket_timer, this, &when,
- &(sock->ev))) {
- rad_panic("Failed to insert event");
- }
+ event_new_fd(this);
}
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ new_listeners = NULL;
+ FD_MUTEX_UNLOCK(&fd_mutex);
}
#endif /* HAVE_PTHREAD_H */
#endif /* WITH_PROXY */
#endif /* WITH_TCP */
}
-#ifndef WITH_SELF_PIPE
+#ifndef HAVE_PTHREAD_H
void radius_signal_self(int flag)
{
- handle_signal_self(flag);
+ return handle_signal_self(flag);
}
+
#else
+static int self_pipe[2] = { -1, -1 };
+
/*
* Inform ourselves that we received a signal.
*/
buffer[0] |= flag;
- write(self_pipe[1], buffer, 1);
+ if (write(self_pipe[1], buffer, 1) < 0) fr_exit(0);
}
handle_signal_self(buffer[0]);
}
-#endif
+#endif /* HAVE_PTHREAD_H */
/***********************************************************************
*
time(&fr_start_time);
- /*
- * radius_event_init() must be called first
- */
- rad_assert(el);
- if (fr_start_time == (time_t)-1) return 0;
+ if (!check_config) {
+ /*
+ * radius_event_init() must be called first
+ */
+ rad_assert(el);
- pl = fr_packet_list_create(0);
- if (!pl) return 0; /* leak el */
+ pl = fr_packet_list_create(0);
+ if (!pl) return 0; /* leak el */
+ }
request_num_counter = 0;
#ifdef WITH_PROXY
- if (mainconfig.proxy_requests) {
+ if (main_config.proxy_requests) {
/*
* Create the tree for managing proxied requests and
* responses.
fr_exit(1);
}
#endif
+
+ /*
+ * The "init_delay" is set to "response_window".
+ * Reset it to half of "response_window" in order
+ * to give the event loop enough time to service
+ * the event before hitting "response_window".
+ */
+ main_config.init_delay.tv_usec += (main_config.init_delay.tv_sec & 0x01) * USEC;
+ main_config.init_delay.tv_usec >>= 1;
+ main_config.init_delay.tv_sec >>= 1;
+
}
#endif
if (check_config) {
DEBUG("%s: #### Skipping IP addresses and Ports ####",
- mainconfig.name);
+ main_config.name);
if (listen_init(cs, &head, spawn_flag) < 0) {
fflush(NULL);
fr_exit(1);
return 1;
}
-#ifdef WITH_SELF_PIPE
+#ifdef HAVE_PTHREAD_H
/*
* Child threads need a pipe to signal us, as do the
* signal handlers.
ERROR("Failed creating handler for signals");
fr_exit(1);
}
-#endif /* WITH_SELF_PIPE */
+#endif
DEBUG("%s: #### Opening IP addresses and Ports ####",
- mainconfig.name);
+ main_config.name);
/*
* The server temporarily switches to an unprivileged
fr_exit_now(1);
}
- mainconfig.listen = head;
+ main_config.listen = head;
/*
* At this point, no one has any business *ever* going
{
REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
+ VERIFY_REQUEST(request);
+
request->master_state = REQUEST_STOP_PROCESSING;
#ifdef HAVE_PTHREAD_H
{
REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
+ VERIFY_REQUEST(request);
+
request->master_state = REQUEST_STOP_PROCESSING;
/*
request->in_request_hash = false;
if (request->ev) fr_event_delete(el, &request->ev);
- if (mainconfig.memory_report) {
+ if (main_config.memory_report) {
RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
request->packet->id,
(unsigned int) (request->timestamp - fr_start_time));
}
#endif
- request_free(&request);
+ talloc_free(request);
/*
* Delete it from the list, and continue;
* Walk the lists again, ensuring that all
* requests are done.
*/
- if (mainconfig.memory_report) {
+ if (main_config.memory_report) {
int num;
#ifdef WITH_PROXY