Defines the state machines that control how requests are processed. More...
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/process.h>
#include <freeradius-devel/modules.h>
#include <freeradius-devel/state.h>
#include <freeradius-devel/rad_assert.h>
#include <freeradius-devel/detail.h>
#include <signal.h>
#include <fcntl.h>
Go to the source code of this file.
Macros | |
#define | ASSERT_MASTER |
#define | CHECK_FOR_STOP do { if (request->master_state == REQUEST_STOP_PROCESSING) {request_done(request, FR_ACTION_DONE);return;}} while (0) |
#define | COA_SEPARATE if (request->coa) coa_separate(request->coa); |
#define | FD_MUTEX_LOCK(_x) |
#define | FD_MUTEX_UNLOCK(_x) |
#define | FINAL_STATE(_x) NO_CHILD_THREAD; request->component = "<" #_x ">"; request->module = ""; request->child_state = _x |
#define | INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); } |
#define | NO_CHILD_THREAD |
#define | PTHREAD_MUTEX_LOCK(_x) |
#define | PTHREAD_MUTEX_UNLOCK(_x) |
#define | rad_panic(x) _rad_panic(__FILE__, __LINE__, x) |
#define | STATE_MACHINE_DECL(_x) static void _x(REQUEST *request, int action) |
Declare a state in the state machine. More... | |
#define | STATE_MACHINE_TIMER(_x) state_machine_timer(__FILE__, __LINE__, request, &when, _x) |
Insert REQUEST back into the event heap, to continue executing at a future time. More... | |
#define | TRACE_STATE_MACHINE {} |
#define | USEC (1000000) |
#define | we_are_master(_x) (1) |
Functions | |
static NEVER_RETURNS void | _rad_panic (char const *file, unsigned int line, char const *msg) |
static void | add_jitter (struct timeval *when) |
static void | check_proxy (rad_listen_t *head) |
static void | coa_no_reply (REQUEST *request, int action) |
Process a request after the CoA has timed out. More... | |
static void | coa_retransmit (REQUEST *request) |
static void | coa_running (REQUEST *request, int action) |
Process the request after receiving a coa reply. More... | |
static void | coa_separate (REQUEST *request) |
static void | coa_wait_for_reply (REQUEST *request, int action) |
Wait for a reply after originating a CoA a request. More... | |
static void | create_default_proxy_listener (int af) |
static int | eol_listener (void *ctx, void *data) |
static int | eol_proxy_listener (void *ctx, void *data) |
static int | event_new_fd (rad_listen_t *this) |
static void | event_poll_detail (void *ctx, struct timeval *now) |
static void | event_socket_handler (fr_event_list_t *xel, UNUSED int fd, void *ctx) |
static void | event_status (struct timeval *wake) |
static void | handle_signal_self (int flag) |
static void | home_trigger (home_server_t *home, char const *trigger) |
static int | insert_into_proxy_hash (REQUEST *request) |
static void | listener_free_cb (void *ctx, UNUSED struct timeval *now) |
static void | mark_home_server_alive (REQUEST *request, home_server_t *home) |
void | mark_home_server_dead (home_server_t *home, struct timeval *when) |
static void | mark_home_server_zombie (home_server_t *home, struct timeval *now, struct timeval *response_window) |
static int | null_handler (UNUSED REQUEST *request) |
static int | packet_entry_cmp (void const *one, void const *two) |
static void | ping_home_server (void *ctx, struct timeval *now) |
static int | process_proxy_reply (REQUEST *request, RADIUS_PACKET *reply) |
static int | proxy_delete_cb (UNUSED void *ctx, void *data) |
static int | proxy_eol_cb (void *ctx, void *data) |
static void | proxy_no_reply (REQUEST *request, int action) |
Process a request after the proxy has timed out. More... | |
static void | proxy_reply_too_late (REQUEST *request) |
static void | proxy_running (REQUEST *request, int action) |
Process the request after receiving a proxy reply. More... | |
static int | proxy_to_virtual_server (REQUEST *request) |
static void | proxy_wait_for_reply (REQUEST *request, int action) |
Wait for a reply after proxying a request. More... | |
void | radius_event_free (void) |
int | radius_event_init (TALLOC_CTX *ctx) |
fr_event_list_t * | radius_event_list_corral (UNUSED event_corral_t hint) |
int | radius_event_process (void) |
int | radius_event_start (bool have_children) |
void | radius_signal_self (int flag) |
void | radius_update_listener (rad_listen_t *this) |
static void | remove_from_proxy_hash (REQUEST *request) |
static void | remove_from_proxy_hash_nl (REQUEST *request, bool yank) |
static void | request_cleanup_delay (REQUEST *request, int action) |
Sit on a request until it's time to clean it up. More... | |
static void | request_cleanup_delay_init (REQUEST *request) |
static void | request_coa_originate (REQUEST *request) |
static int | request_delete_cb (UNUSED void *ctx, void *data) |
static void | request_done (REQUEST *request, int action) |
Mark a request DONE and clean it up. More... | |
static void | request_dup (REQUEST *request) |
static void | request_finish (REQUEST *request, int action) |
Do the final processing of a request before we reply to the NAS. More... | |
static void | request_free (REQUEST *request) |
static int | request_init_delay (REQUEST *request) |
static bool | request_max_time (REQUEST *request) |
static void | request_ping (REQUEST *request, int action) |
Ping a home server. More... | |
static int | request_pre_handler (REQUEST *request, UNUSED int action) |
static int | request_proxy (REQUEST *request, int retransmit) CC_HINT(nonnull) |
static int | request_proxy_anew (REQUEST *request) |
int | request_proxy_reply (RADIUS_PACKET *packet) |
static void | request_queue_or_run (REQUEST *request, fr_request_process_t process) |
int | request_receive (TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet, RADCLIENT *client, RAD_REQUEST_FUNP fun) |
static void | request_response_delay (REQUEST *request, int action) |
Sit on a request until it's time to respond to it. More... | |
static struct timeval * | request_response_window (REQUEST *request) |
static void | request_running (REQUEST *request, int action) |
Process a request from a client. More... | |
static REQUEST * | request_setup (TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet, RADCLIENT *client, RAD_REQUEST_FUNP fun) |
static void | request_timer (void *ctx, struct timeval *now) |
static void | request_timer (void *ctx, UNUSED struct timeval *now) |
static int | request_will_proxy (REQUEST *request) |
Determine if a REQUEST needs to be proxied, and perform pre-proxy operations. More... | |
void | revive_home_server (void *ctx, UNUSED struct timeval *now) |
static int | setup_post_proxy_fail (REQUEST *request) |
STATE_MACHINE_DECL (request_ping) | |
static void | state_machine_timer (char const *file, int line, REQUEST *request, struct timeval *when, fr_state_action_t action) |
Insert REQUEST back into the event heap, to continue executing at a future time. More... | |
static void | tcp_socket_timer (void *ctx, struct timeval *now) |
Variables | |
static char const * | action_codes [] |
fr_cond_t * | debug_condition |
fr_log_t | debug_log |
static fr_event_list_t * | el = NULL |
time_t | fr_start_time = (time_t)-1 |
static bool | just_started = true |
static rbtree_t * | pl = NULL |
static TALLOC_CTX * | proxy_ctx = NULL |
static fr_packet_list_t * | proxy_list = NULL |
pid_t | radius_pid |
static int | request_num_counter = 1 |
static bool | spawn_workers = false |
Defines the state machines that control how requests are processed.
Definition in file process.c.
#define CHECK_FOR_STOP do { if (request->master_state == REQUEST_STOP_PROCESSING) {request_done(request, FR_ACTION_DONE);return;}} while (0) |
#define COA_SEPARATE if (request->coa) coa_separate(request->coa); |
#define FINAL_STATE | ( | _x | ) | NO_CHILD_THREAD; request->component = "<" #_x ">"; request->module = ""; request->child_state = _x |
#define INSERT_EVENT | ( | _function, | |
_ctx | |||
) | if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); } |
#define rad_panic | ( | x | ) | _rad_panic(__FILE__, __LINE__, x) |
#define STATE_MACHINE_DECL | ( | _x | ) | static void _x(REQUEST *request, int action) |
#define STATE_MACHINE_TIMER | ( | _x | ) | state_machine_timer(__FILE__, __LINE__, request, &when, _x) |
#define USEC (1000000) |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
Wait for a reply after originating a CoA a request.
Retransmit the proxied packet, or time out and go to coa_no_reply. Mark the home server unresponsive, etc.
If we do receive a reply, we transition to coa_running.
Definition at line 4359 of file process.c.
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
void mark_home_server_dead | ( | home_server_t * | home, |
struct timeval * | when | ||
) |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
Wait for a reply after proxying a request.
Retransmit the proxied packet, or time out and go to proxy_no_reply. Mark the home server unresponsive, etc.
If we do receive a reply, we transition to proxy_running.
Definition at line 3720 of file process.c.
void radius_event_free | ( | void | ) |
int radius_event_init | ( | TALLOC_CTX * | ctx | ) |
fr_event_list_t* radius_event_list_corral | ( | UNUSED event_corral_t | hint | ) |
int radius_event_process | ( | void | ) |
int radius_event_start | ( | bool | have_children | ) |
void radius_signal_self | ( | int | flag | ) |
void radius_update_listener | ( | rad_listen_t * | this | ) |
|
static |
|
static |
|
static |
Sit on a request until it's time to clean it up.
A NAS may not see a response from the server. When the NAS retransmits, we want to be able to send a cached reply back. The alternative is to re-process the packet, which does bad things for EAP, among others.
IF we do see a NAS retransmit, we extend the cleanup delay, because the NAS might miss our cached reply.
Otherwise, once we reach cleanup_delay, we transition to DONE.
Definition at line 1002 of file process.c.
|
static |
|
static |
|
static |
|
static |
Mark a request DONE and clean it up.
When a request is DONE, it can have ties to a number of other portions of the server. The request hash, proxy hash, events, child threads, etc. This function takes care of either cleaning up the request, or managing the timers to wait for the ties to be removed.
Definition at line 528 of file process.c.
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
int request_proxy_reply | ( | RADIUS_PACKET * | packet | ) |
|
static |
int request_receive | ( | TALLOC_CTX * | ctx, |
rad_listen_t * | listener, | ||
RADIUS_PACKET * | packet, | ||
RADCLIENT * | client, | ||
RAD_REQUEST_FUNP | fun | ||
) |
|
static |
Sit on a request until it's time to respond to it.
For security reasons, rejects (and maybe some other) packets are delayed for a while before we respond. This delay means that badly behaved NASes don't hammer the server with authentication attempts.
Otherwise, once we reach response_delay, we send the reply, and transition to cleanup_delay.
Definition at line 1082 of file process.c.
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
Determine if a REQUEST needs to be proxied, and perform pre-proxy operations.
Whether a request will be proxied is determined by the attributes present in request->config. If any of the following attributes are found, the request may be proxied.
The key attributes are:
Certain packet types such as PW_CODE_STATUS_SERVER will never be proxied.
If request should be proxied, will:
request | The REQUEST to evaluate for proxying. |
Definition at line 2743 of file process.c.
void revive_home_server | ( | void * | ctx, |
UNUSED struct timeval * | now | ||
) |
|
static |
STATE_MACHINE_DECL | ( | request_ping | ) |
|
inlinestatic |
Insert REQUEST back into the event heap, to continue executing at a future time.
file | the state machine timer call occurred in. |
line | the state machine timer call occurred on. |
request | to set add the timer event for. |
when | the event should fine. |
action | to perform when we resume processing the request. |
Definition at line 131 of file process.c.
|
static |
|
static |
fr_cond_t* debug_condition |
fr_log_t debug_log |
|
static |
|
static |
Time sequence of a request
M: Max request time. If the request hits this timer, it is forcibly stopped.
Other considerations include duplicate and conflicting packets. When a dupicate packet is received, it is ignored until we've reached Y, as no response is ready. If the reply is a reject, duplicates are ignored until J, when we're ready to send the reply. In between the reply being sent (Y or J), and C, the server responds to duplicates by sending the cached reply.
Conflicting packets are sent in 2 situations.
The first is in between R and Y. In that case, we consider it as a hint that we're taking too long, and the NAS has given up on the request. We then behave just as if the M timer was reached, and we discard the current request. This allows us to process the new one.
The second case is when we're at Y, but we haven't yet finished processing the request. This is a race condition in the threading code (avoiding locks is faster). It means that a thread has actually encoded and sent the reply, and that the NAS has responded with a new packet. The server can then safely mark the current request as "OK to delete", and behaves just as if the M timer was reached. This usually happens only in high-load situations.
Duplicate packets are sent when the NAS thinks we're taking too long, and wants a reply. From R-Y, duplicates are ignored. From Y-J (for Access-Rejects), duplicates are also ignored. From Y-C, duplicates get a duplicate reply. And, they cause the "cleanup_delay" time to be extended. This extension means that we're more likely to send a duplicate reply (if we have one), or to suppress processing the packet twice if we didn't reply to it.
All functions in this file should be thread-safe, and should assume thet the REQUEST structure is being accessed simultaneously by the main thread, and by the child worker threads. This means that timers, etc. cannot be updated in the child thread.
Instead, the master thread periodically calls request->process with action TIMER. It's up to the individual functions to determine how to handle that. They need to check if they're being called from a child thread or the master, and then do different things based on that.
pid_t radius_pid |