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;
152 uint8_t *partial, *end, *next, *p, *record_end;
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;
324 ERROR(
"proto_detail (%s): Malformed line found at offset %zu in file %s",
339 if ((p + 2) >= end) {
349 while ((p < end) && !isspace((
uint8_t) *p)) p++;
365 if (memcmp(p,
" = ", 3) != 0) {
366 ERROR(
"proto_detail (%s): Malformed line found at offset %zu: %.*s of file %s",
387 packet_len = next -
buffer;
388 *leftover = end - next;
390 MPRINT(
"FOUND next at %zd, leftover is %zd", packet_len, *leftover);
392 }
else if (!thread->
eof) {
393 if ((
size_t) (end -
buffer) == buffer_len) {
394 ERROR(
"proto_detail (%s): Too large entry (>%d bytes) found at offset %zu: %.*s of file %s",
395 thread->
name, (
int) buffer_len,
408 MPRINT(
"Not at EOF, and no next. Leftover is %zd", *leftover);
417 packet_len = end -
buffer;
420 MPRINT(
"NO end of record, but at EOF, found %zd leftover is 0", packet_len);
428 if (packet_len >
inst->parent->max_packet_size) {
429 DEBUG(
"Ignoring 'too large' entry at offset %zu of %s",
431 DEBUG(
"Entry size %lu is greater than allowed maximum %u",
432 packet_len,
inst->parent->max_packet_size);
434 MPRINT(
"Skipping record");
436 memmove(
buffer, next, (end - next));
437 data_size = (end - next);
445 if (end ==
buffer)
return 0;
457 record_end =
buffer + packet_len;
461 while (p < record_end) {
468 if (p == record_end)
break;
470 if (((record_end - p) >= 5) &&
471 (memcmp(p,
"\tDone", 5) == 0)) {
475 if (((record_end - p) > 10) &&
476 (memcmp(p,
"\tTimestamp", 10) == 0)) {
491 if (
inst->retransmit) {
492 track->
packet = talloc_memdup(track,
buffer, packet_len);
510 thread->
closing = (*leftover == 0);
526 if (*leftover) (void) lseek(thread->
fd, thread->
read_offset - 1, SEEK_SET);
545 DEBUG(
"%s - retransmitting packet %d", thread->
name, track->
id);
563 (void) lseek(thread->
fd, 0, SEEK_SET);
577 if (buffer_len < 1)
return -1;
583 if (!
inst->retransmit)
goto mark_done;
592 DEBUG(
"%s - packet %d failed after %u retransmissions",
599 DEBUG(
"%s - packet %d failed after %u seconds",
606 DEBUG(
"%s - packet %d failed during processing. Will retransmit in %.6fs",
611 ERROR(
"%s - Failed inserting retransmission timeout", thread->
name);
631 if (write(thread->
fd,
"Done", 4) < 0) {
652 (void) lseek(thread->
fd, 0, SEEK_SET);
665 MPRINT(
"WRITE ASKED TO CLOSE");
669 MPRINT(
"WRITE RETURN B %ld", buffer_len);
686 if (thread->
fd < 0) {
690 if (thread->
fd < 0) {
699 if (
inst->track_progress) {
702 if (fstat(thread->
fd, &buf) < 0) {
750 DEBUG(
"Closing %sdetail worker file %s", thread->
outstanding == 0 ?
"and deleting " :
"", thread->
name);
770 if (
inst->parent->exit_when_done) {
771 INFO(
"Done reading detail files, process will now exit");
804 DEBUG(
"Detail worker %s had file system unmounted. Stopping.", thread->
name);
823 memset(&funcs, 0,
sizeof(funcs));
824 funcs.revoke = mod_revoke;
827 WARN(
"Failed to add event watching for unmounted file system");
849 if (!
inst->client)
return 0;
852 client->
ipaddr.
addr.v4.s_addr = htonl(INADDR_NONE);
856 client->
nas_type = talloc_strdup(client,
"other");
878 if (
inst->track_progress) {
881 inst->mode = O_RDONLY;
884 if (
inst->retransmit) {
914 .name =
"detail_work",
921 .default_message_size = 65536,
922 .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_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.
dl_module_inst_t const * dl_module_instance_by_data(void const *data)
Lookup a dl_module_inst_t via instance data.
void *_CONST data
Module instance's parsed configuration.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
CONF_SECTION *_CONST conf
Module's instance configuration.
dl_module_inst_t const *_CONST parent
Parent module's instance (if any).
#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::@121 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.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
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.
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
static int mod_bootstrap(module_inst_ctx_t const *mctx)
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[]
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