26 #include <freeradius-devel/io/application.h>
27 #include <freeradius-devel/io/listen.h>
28 #include <freeradius-devel/io/schedule.h>
30 #include <freeradius-devel/server/main_config.h>
31 #include <freeradius-devel/server/protocol.h>
33 #include <freeradius-devel/util/syserror.h>
34 #include <freeradius-devel/util/misc.h>
46 #error proto_detail_file requires <glob.h>
94 return inst->parent->work_io->decode(
inst->parent->work_io_instance, request,
data, data_len);
117 bool has_worker =
false;
123 if (has_worker)
return;
138 if (
inst->poll_interval == 0) {
146 li->
fd = thread->
fd = open(
inst->directory, oflag);
147 if (thread->
fd < 0) {
152 li->
fd = thread->
fd = -1;
175 char const *filename;
179 DEBUG3(
"proto_detail (%s): polling for detail files in %s",
182 memset(&files, 0,
sizeof(files));
183 if (glob(
inst->filename, 0, NULL, &files) != 0) {
185 DEBUG3(
"proto_detail (%s): no matching files for %s",
197 for (i = 0; i < files.gl_pathc; i++) {
198 if (stat(files.gl_pathv[i], &st) < 0)
continue;
200 if ((i == 0) || (st.st_ctime < chtime)) {
201 chtime = st.st_ctime;
209 if (found < 0)
goto noop;
214 filename = files.gl_pathv[found];
216 DEBUG(
"proto_detail (%s): Renaming %s -> %s", thread->
name, filename,
inst->filename_work);
217 if (rename(filename,
inst->filename_work) < 0) {
218 ERROR(
"detail (%s): Failed renaming %s to %s: %s",
228 return open(
inst->filename_work,
inst->mode);
254 DEBUG3(
"proto_detail (%s): Trying to lock %s", thread->
name,
inst->filename_work);
262 DEBUG3(
"proto_detail (%s): Failed locking %s: %s",
280 DEBUG3(
"proto_detail (%s): Waiting %.6fs for lock on file %s",
285 ERROR(
"Failed inserting retry timer for %s",
inst->filename_work);
290 DEBUG3(
"proto_detail (%s): Obtained lock and starting to process file %s",
296 if (fstat(fd, &st) < 0) {
297 ERROR(
"Failed opening %s: %s",
inst->filename_work,
299 unlink(
inst->filename_work);
305 DEBUG3(
"proto_detail (%s): %s file is empty, ignoring it.",
307 unlink(
inst->filename_work);
343 li->
fd = work->
fd = dup(fd);
345 DEBUG(
"proto_detail (%s): Failed opening %s: %s",
360 &funcs, NULL, thread) < 0) {
361 PERROR(
"Failed adding work socket to event loop");
405 PERROR(
"Failed removing DELETE callback when opening work file");
434 DEBUG(
"proto_detail (%s): Deleted %s", thread->
name,
inst->filename_work);
441 if (fd == thread->
fd)
return;
444 ERROR(
"Received DELETE for FD %d, when we were expecting one on FD %d - ignoring it",
450 PERROR(
"Failed removing DELETE callback after deletion");
493 DEBUG3(
"proto_detail (%s): worker %s is still alive, waiting for it to finish.",
504 DEBUG3(
"Trying to open %s",
inst->filename_work);
505 fd = open(
inst->filename_work,
inst->mode);
512 if (errno != ENOENT) {
513 DEBUG(
"proto_detail (%s): Failed opening %s: %s",
533 if (!
inst->poll_interval)
return;
539 if (
inst->immediate && triggered_by_delete)
return;
545 if (
inst->immediate &&
inst->parent->exit_when_done) {
546 ERROR(
"Input file does not exist");
553 DEBUG3(
"Waiting %d.000000s for new files in %s",
inst->poll_interval, thread->
name);
557 ERROR(
"Failed inserting poll timer for %s",
inst->filename_work);
571 if (rcode < 0)
goto delay;
576 if (rcode == 1)
goto retry;
598 if (
inst->immediate) {
668 cf_log_err(
conf,
"Cannot start detail file reader due to Linux limitations.");
669 cf_log_err(
conf,
"Please set 'allow_core_dumps = true' in the main configuration file.");
692 inst->directory = p = talloc_strdup(
inst,
inst->filename);
702 if (!
inst->filename_work) {
711 if (
inst->parent->exit_when_done && !
inst->immediate) {
712 cf_log_warn(
conf,
"Ignoring 'exit_when_done' due to 'immediate' flag not being set");
713 inst->parent->exit_when_done =
false;
762 PERROR(
"Failed removing DELETE callback on detach");
782 .name =
"detail_file",
788 .default_message_size = 65536,
789 .default_reply_size = 32,
static int const char char buffer[256]
fr_io_close_t close
Close the transport.
fr_io_open_t open
Open a new socket for listening, or accept/connect a new connection.
module_t common
Common fields to all loadable modules.
fr_io_data_write_t write
Write from a data buffer to a socket.
fr_io_name_t get_name
get the socket name
Public structure describing an I/O path for a protocol.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#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_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
fr_dcursor_eval_t void const * uctx
#define fr_exit(_x)
Exit, producing a log message in debug builds.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
@ FR_EVENT_FILTER_VNODE
Filter for vnode subfilters.
#define fr_event_filter_insert(...)
fr_event_fd_cb_t delete
The file was deleted.
#define fr_event_timer_in(...)
Callbacks for the FR_EVENT_FILTER_VNODE filter.
size_t num_messages
for the message ring buffer
bool non_socket_listener
special internal listener that does not use sockets.
char const * name
printable name for this socket - set by open
void const * app_instance
size_t default_message_size
copied from app_io, but may be changed
void const * app_io_instance
I/O path configuration context.
CONF_SECTION * server_cs
CONF_SECTION of the server.
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
bool needs_full_setup
Set to true to avoid the short cut when adding the listener.
fr_app_io_t const * app_io
I/O path functions.
int fr_network_listen_delete(fr_network_t *nr, fr_listen_t *li)
Delete a socket from a network.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
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.
main_config_t const * main_config
Main server configuration.
bool allow_core_dumps
Whether the server is allowed to drop a core when receiving a fatal signal.
static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, fr_time_t request_time, uint8_t *buffer, size_t buffer_len, size_t written)
int rad_lockfd_nonblock(int fd, int lock_len)
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
Detail master protocol handler.
proto_detail_t * parent
The module that spawned us!
proto_detail_work_thread_t * file_parent
thread instance of the directory reader that spawned us
fr_time_delta_t lock_interval
interval between trying the locks.
fr_listen_t * listen
talloc_parent() is slow
char const * filename
file name, usually with wildcards
CONF_SECTION * server_cs
server CS for this listener
char const * name
debug name for printing
fr_event_timer_t const * ev
for detail file timers.
int num_workers
number of workers
fr_event_list_t * el
for various timers
pthread_mutex_t worker_mutex
for the workers
char const * filename_work
work file name
proto_detail_work_t const * inst
instance data
int vnode_fd
file descriptor for vnode_delete
fr_network_t * nr
for Linux-specific callbacks
static void mod_vnode_extend(fr_listen_t *li, UNUSED uint32_t fflags)
static const conf_parser_t file_listen_config[]
fr_app_io_t proto_detail_file
Private interface for use by proto_detail_file.
struct proto_detail_work_s proto_detail_file_t
static void work_retry_timer(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
static int8_t _detail_file_cmp(void const *one, void const *two)
Compare two thread instances based on node pointer.
static pthread_mutex_t detail_file_mutex
static int mod_decode(void const *instance, request_t *request, uint8_t *const data, size_t data_len)
static int work_rename(proto_detail_file_thread_t *thread)
static int mod_open(fr_listen_t *li)
Open a detail listener.
static char const * mod_name(fr_listen_t *li)
static fr_rb_tree_t * detail_file_tree
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, UNUSED void *nr)
Set the event list for a new IO instance.
static int mod_close(fr_listen_t *li)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static void work_init(proto_detail_file_thread_t *thread, bool triggered_by_delete)
Start processing a new work file.
static void mod_vnode_delete(fr_event_list_t *el, int fd, UNUSED int fflags, void *ctx)
static int work_exists(proto_detail_file_thread_t *thread, int fd)
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
The main red black tree structure.
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
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
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 fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
static fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b)
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_delta_wrap(_time)
static fr_time_delta_t fr_time_delta_div(fr_time_delta_t a, fr_time_delta_t b)
#define fr_time_delta_gt(_a, _b)
A time delta, a difference in time measured in nanoseconds.
static fr_event_list_t * el