26 #include <freeradius-devel/server/protocol.h>
27 #include <freeradius-devel/server/pair.h>
28 #include <freeradius-devel/server/main_loop.h>
29 #include <freeradius-devel/io/application.h>
30 #include <freeradius-devel/io/listen.h>
31 #include <freeradius-devel/util/syserror.h>
49 #define MPRINT(_x, ...)
122 request->client =
inst->client;
124 request->packet->id = track->
id;
125 request->reply->id = track->
id;
234 partial =
buffer + *leftover;
236 MPRINT(
"READ leftover %zd", *leftover);
244 room = buffer_len - *leftover;
246 data_size = read(thread->
fd, partial, room);
248 ERROR(
"proto_detail (%s): Failed reading file %s: %s",
253 MPRINT(
"GOT %zd bytes", data_size);
265 MPRINT(
"Set EOF data_size %ld vs room %ld", data_size, room);
268 end = partial + data_size;
282 stopped_search = end;
301 if ((p + 1) == end) {
315 stopped_search =
next;
325 ERROR(
"proto_detail (%s): Missing tab indent at %s[%u], offset from start of file %zu",
341 if ((p + 2) >= end) {
351 while ((p < end) && !isspace((
uint8_t) *p)) p++;
367 if (memcmp(p,
" = ", 3) != 0) {
368 ERROR(
"proto_detail (%s): Missing pair assignment operator at %s[%u], offset from start of file %zu: %.*s",
390 *leftover = end -
next;
392 MPRINT(
"FOUND next at %zd, leftover is %zd", packet_len, *leftover);
394 }
else if (!thread->
eof) {
395 if ((
size_t) (end -
buffer) == buffer_len) {
396 ERROR(
"proto_detail (%s): Too large entry (>%d bytes) found at offset %zu: %.*s of file %s",
397 thread->
name, (
int) buffer_len,
410 MPRINT(
"Not at EOF, and no next. Leftover is %zd", *leftover);
419 packet_len = end -
buffer;
422 MPRINT(
"NO end of record, but at EOF, found %zd leftover is 0", packet_len);
430 if (packet_len >
inst->parent->max_packet_size) {
431 DEBUG(
"Ignoring 'too large' entry at offset %zu of %s",
433 DEBUG(
"Entry size %lu is greater than allowed maximum %u",
434 packet_len,
inst->parent->max_packet_size);
436 MPRINT(
"Skipping record");
439 data_size = (end -
next);
447 if (end ==
buffer)
return 0;
459 record_end =
buffer + packet_len;
463 while (p < record_end) {
470 if (p == record_end)
break;
472 if (((record_end - p) >= 5) &&
473 (memcmp(p,
"\tDone", 5) == 0)) {
477 if (((record_end - p) > 10) &&
478 (memcmp(p,
"\tTimestamp", 10) == 0)) {
493 if (
inst->retransmit) {
512 thread->
closing = (*leftover == 0);
528 if (*leftover) (void) lseek(thread->
fd, thread->
read_offset - 1, SEEK_SET);
547 DEBUG(
"%s - retransmitting packet %d", thread->
name, track->
id);
565 (void) lseek(thread->
fd, 0, SEEK_SET);
579 if (buffer_len < 1)
return -1;
585 if (!
inst->retransmit)
goto mark_done;
594 DEBUG(
"%s - packet %d failed after %u retransmissions",
601 DEBUG(
"%s - packet %d failed after %u seconds",
608 DEBUG(
"%s - packet %d failed during processing. Will retransmit in %.6fs",
613 ERROR(
"%s - Failed inserting retransmission timeout", thread->
name);
633 if (write(thread->
fd,
"Done", 4) < 0) {
654 (void) lseek(thread->
fd, 0, SEEK_SET);
667 MPRINT(
"WRITE ASKED TO CLOSE");
671 MPRINT(
"WRITE RETURN B %ld", buffer_len);
688 if (thread->
fd < 0) {
692 if (thread->
fd < 0) {
701 if (
inst->track_progress) {
704 if (fstat(thread->
fd, &buf) < 0) {
752 DEBUG(
"Closing %sdetail worker file %s", thread->
outstanding == 0 ?
"and deleting " :
"", thread->
name);
764 if (
inst->parent->exit_when_done) {
765 INFO(
"Done reading detail files, process will now exit");
798 DEBUG(
"Detail worker %s had file system unmounted. Stopping.", thread->
name);
817 memset(&funcs, 0,
sizeof(funcs));
818 funcs.revoke = mod_revoke;
821 WARN(
"Failed to add event watching for unmounted file system");
847 if (
inst->track_progress) {
850 inst->mode = O_RDONLY;
853 if (
inst->retransmit) {
873 if (!
inst->client)
return 0;
876 client->
ipaddr.
addr.v4.s_addr = htonl(INADDR_NONE);
880 client->
nas_type = talloc_strdup(client,
"other");
892 .name =
"detail_work",
898 .default_message_size = 65536,
899 .default_reply_size = 32,
static int const char char buffer[256]
module_t common
Common fields to all loadable modules.
Public structure describing an I/O path for a protocol.
#define CONF_PARSER_TERMINATOR
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
static int max_outstanding
fr_dcursor_eval_t void const * uctx
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Entry in a doubly linked list.
@ FR_EVENT_FILTER_VNODE
Filter for vnode subfilters.
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
#define fr_event_filter_update(...)
#define fr_event_filter_insert(...)
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
#define fr_event_timer_at(...)
Callbacks for the FR_EVENT_FILTER_IO filter.
Structure describing a modification to a filter's state.
Callbacks for the FR_EVENT_FILTER_VNODE filter.
union fr_ipaddr_t::@130 addr
void const * app_io_instance
I/O path configuration context.
void * thread_instance
thread / socket context
bool no_write_callback
sometimes we don't need to do writes
int fd
file descriptor for this socket - set by open
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
char const * secret
Secret PSK.
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
char const * nas_type
Type of client (arbitrary).
char const * longname
Client identifier.
char const * shortname
Client nickname.
Describes a host allowed to send packets to the server.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Stores all information relating to an event list.
void main_loop_signal_raise(int flag)
@ RADIUS_SIGNAL_SELF_TERM
@ FR_TYPE_UINT32
32 Bit unsigned integer.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
Detail master protocol handler.
struct proto_detail_work_s proto_detail_work_t
size_t last_search
where we last searched in the buffer MUST be offset, as the buffers can change.
proto_detail_work_thread_t * file_parent
thread instance of the directory reader that spawned us
bool paused
Is reading paused?
int count
number of packets we read from this file.
unsigned int last_line
line number of the last record read.
bool eof
are we at EOF on reading?
fr_listen_t * listen
talloc_parent() is slow
char const * name
debug name for printing
int num_workers
number of workers
uint16_t max_outstanding
number of packets to run in parallel
fr_event_list_t * el
for various timers
off_t file_size
size of the file
uint8_t * leftover_buffer
pthread_mutex_t worker_mutex
for the workers
char const * filename_work
work file name
off_t header_offset
offset of the current header we're reading
proto_detail_work_t const * inst
instance data
fr_dlist_head_t list
for retransmissions
bool closing
we should be closing the file
off_t read_offset
where we're reading from in filename_work
uint32_t outstanding
number of currently outstanding records;
fr_network_t * nr
for Linux-specific callbacks
fr_dict_attr_autoload_t proto_detail_work_dict_attr[]
static const conf_parser_t file_listen_config[]
static void work_retransmit(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
fr_event_timer_t const * ev
retransmission timer
static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *const data, UNUSED size_t data_len)
static fr_dict_t const * dict_freeradius
proto_detail_work_thread_t * parent
talloc_parent is SLOW!
fr_dlist_t entry
for the retransmission list
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new IO instance.
static int mod_open(fr_listen_t *li)
Open a detail listener.
size_t packet_len
for retransmissions
fr_retry_t retry
our retry timers
uint8_t * packet
for retransmissions
fr_time_t timestamp
when we read the entry.
static char const * mod_name(fr_listen_t *li)
fr_dict_autoload_t proto_detail_work_dict[]
static fr_event_update_t pause_read[]
static conf_parser_t limit_config[]
fr_app_io_t proto_detail_work
Private interface for use by proto_detail_file.
static int mod_close_internal(proto_detail_work_thread_t *thread)
int id
for retransmission counters
static int mod_close(fr_listen_t *li)
Close a detail listener.
off_t done_offset
where we're tracking the status
static fr_dict_attr_t const * attr_packet_transmit_counter
static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t request_time, uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static fr_event_update_t resume_read[]
#define pair_update_request(_attr, _da)
#define REQUEST_VERIFY(_x)
static conf_parser_t retry_config[]
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
module_instance_t const * parent
Parent module's instance (if any).
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_wrap(_time)
#define fr_time_eq(_a, _b)
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
static fr_event_list_t * el
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
fr_time_t start
when we started the retransmission
fr_time_delta_t rt
retransmit interval
@ FR_RETRY_MRC
reached maximum retransmission count
@ FR_RETRY_MRD
reached maximum retransmission duration
uint32_t count
number of sent packets
fr_time_t next
when the next timer should be set