25 RCSID(
"$Id: 9c7f4c54b722cd39885a1ac1a8a7e1684ed4262b $")
27 #define LOG_PREFIX nr->name
29 #define LOG_DST nr->log
31 #include <freeradius-devel/util/event.h>
32 #include <freeradius-devel/util/misc.h>
33 #include <freeradius-devel/util/rand.h>
34 #include <freeradius-devel/util/rb.h>
35 #include <freeradius-devel/util/syserror.h>
36 #include <freeradius-devel/util/atexit.h>
37 #include <freeradius-devel/util/talloc.h>
39 #include <freeradius-devel/io/channel.h>
40 #include <freeradius-devel/io/control.h>
41 #include <freeradius-devel/io/listen.h>
42 #include <freeradius-devel/io/network.h>
43 #include <freeradius-devel/io/queue.h>
44 #include <freeradius-devel/io/ring_buffer.h>
45 #include <freeradius-devel/io/worker.h>
47 #define MAX_WORKERS 64
157 static int8_t
reply_cmp(
void const *one,
void const *two)
163 if (ret != 0)
return ret;
174 if (ret != 0)
return ret;
176 return fr_time_cmp(a->reply.request_time, b->reply.request_time);
215 fr_perror(
"Failed allocating memory for network ring buffer");
226 return (pthread_equal(pthread_self(), nr->
thread_id) != 0);
351 void *packet_ctx,
fr_time_t request_time)
359 .data_size = packet_len,
360 .when = request_time,
369 .reply.request_time = request_time,
372 memcpy(&cd.
m.
data, &packet,
sizeof(packet));
373 memcpy(&cd.
packet_ctx, &packet_ctx,
sizeof(packet_ctx));
421 if (li->
app_io->
inject(li, packet, packet_len, recv_time) == 0) {
432 my_inject.
packet = talloc_memdup(NULL, packet, packet_len);
478 #define RTT(_old, _new) fr_time_delta_wrap((fr_time_delta_unwrap(_new) + (fr_time_delta_unwrap(_old) * (IALPHA - 1))) / IALPHA)
498 worker->
cpu_time = cd->reply.cpu_time;
500 worker->
predicted = cd->reply.processing_time;
576 DEBUG3(
"Worker acked our close request");
595 #define OUTSTANDING(_x) ((_x)->stats.in - (_x)->stats.out)
613 "In single-threaded mode and worker is blocked");
626 }
while (two == one);
640 }
else if (cmp > 0) {
651 uint64_t min_outstanding = UINT64_MAX;
659 uint64_t outstanding;
665 if ((outstanding < min_outstanding) || !found) {
667 min_outstanding = outstanding;
669 }
else if (outstanding == min_outstanding) {
781 cd->request.recv_time = recv_time;
864 int num_messages = 0;
878 ERROR(
"Failed allocating message size %zd! - Closing socket",
894 if (num_messages > 16) {
913 if (data_size == 0) {
939 DEBUG3(
"Read %zd byte(s) from FD %u", data_size,
sockfd);
975 PERROR(
"Failed reserving partial packet.");
996 if (priority <= 0)
goto discard;
1045 cd->
m.
when = recv_time;
1101 int fd_errno,
void *ctx)
1109 }
else if (flags & EV_EOF) {
1159 while (cd != NULL) {
1164 cd->reply.request_time,
1171 if (rcode == 0)
goto dead;
1181 if (errno == EWOULDBLOCK) {
1190 ERROR(
"Failed saving pending packet");
1199 PERROR(
"Failed adding write callback to event loop");
1217 if (errno == ECONNREFUSED)
goto dead;
1231 if ((
size_t) rcode < cd->m.data_size) {
1256 PERROR(
"Failed removing write callback from event loop");
1314 if (data_size !=
sizeof(li))
return;
1344 fr_log(nr->
log,
L_DBG, __FILE__, __LINE__,
"Listener %s bound to virtual server %s",
1352 talloc_steal(s, li);
1368 if (num_messages < 8) num_messages = 8;
1371 if (size < (1 << 17)) size = (1 << 17);
1372 if (size > (100 * 1024 * 1024)) size = (100 * 1024 * 1024);
1381 PERROR(
"Failed creating message buffers for network IO");
1394 PERROR(
"Failed adding new socket to network event loop");
1419 fr_log(nr->
log,
L_DBG, __FILE__, __LINE__,
"Listening on %s bound to virtual server %s",
1445 memcpy(&li,
data,
sizeof(li));
1449 talloc_steal(s, li);
1463 if (num_messages < 8) num_messages = 8;
1469 PERROR(
"Failed creating message buffers for directory IO");
1484 PERROR(
"Failed adding directory monitor event loop");
1511 memcpy(&worker,
data, data_size);
1512 (void) talloc_get_type_abort(worker,
fr_worker_t);
1561 fr_assert(data_size ==
sizeof(my_inject));
1563 memcpy(&my_inject,
data, data_size);
1696 len = talloc_array_length(sockets);
1698 for (i = 0; i < len; i++) {
1769 if (read(fd, &
buff,
sizeof(
buff)) < 0) {
1786 DEBUG2(
"Signalled to exit");
1810 bool wait_for_event;
1823 DEBUG4(
"Gathering events - %s", wait_for_event ?
"will wait" :
"Will not wait");
1825 DEBUG4(
"%u event(s) pending%s",
1826 num_events == -1 ? 0 : num_events, num_events == -1 ?
" - event loop exiting" :
"");
1827 if (num_events < 0)
break;
1832 if (num_events > 0) {
1833 DEBUG4(
"Servicing event(s)");
1895 nr->
name = talloc_strdup(nr,
name);
2009 if (num < 0)
return -1;
2010 if (num == 0)
return 0;
2018 if (num <= 5)
return num;
2031 if (!nr->
workers[i])
continue;
2041 fprintf(fp,
"count.in\t%" PRIu64
"\n", nr->
stats.
in);
2042 fprintf(fp,
"count.out\t%" PRIu64
"\n", nr->
stats.
out);
2043 fprintf(fp,
"count.dup\t%" PRIu64
"\n", nr->
stats.
dup);
2044 fprintf(fp,
"count.dropped\t%" PRIu64
"\n", nr->
stats.
dropped);
2077 fprintf(fp_err,
"No such socket number '%s'.\n", info->
argv[0]);
2081 fprintf(fp,
"count.in\t%" PRIu64
"\n", s->
stats.
in);
2082 fprintf(fp,
"count.out\t%" PRIu64
"\n", s->
stats.
out);
2083 fprintf(fp,
"count.dup\t%" PRIu64
"\n", s->
stats.
dup);
2084 fprintf(fp,
"count.dropped\t%" PRIu64
"\n", s->
stats.
dropped);
2094 .help =
"Statistics for network threads.",
2099 .parent =
"stats network",
2103 .help =
"Show statistics for a specific network thread.",
2108 .parent =
"stats network",
2111 .syntax =
"INTEGER",
2113 .help =
"Show statistics for a specific socket",
2120 .help =
"Show information about network threads.",
2125 .parent =
"show network",
2130 .help =
"List the sockets associated with this network thread.",
static int const char char buffer[256]
fr_io_close_t close
Close the transport.
fr_io_data_read_t read
Read from a socket to a data buffer.
module_t common
Common fields to all loadable modules.
fr_io_signal_t error
There was an error on the socket.
fr_app_event_list_set_t event_list_set
Called by the network thread to pass an event list for use by the app_io_t.
fr_io_data_inject_t inject
Inject a packet into a socket.
fr_io_data_vnode_t vnode
Handle notifications that the VNODE has changed.
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.
fr_app_priority_get_t priority
Assign a priority to the packet.
#define fr_atexit_thread_local(_name, _free, _uctx)
fr_atomic_queue_t * fr_atomic_queue_alloc(TALLOC_CTX *ctx, size_t size)
Create fixed-size atomic queue.
Structure to hold the atomic queue.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
void * fr_channel_requestor_uctx_get(fr_channel_t *ch)
Get network-specific data from a channel.
fr_table_num_sorted_t const channel_signals[]
bool fr_channel_recv_reply(fr_channel_t *ch)
Receive a reply message from the channel.
int fr_channel_signal_responder_close(fr_channel_t *ch)
Signal a responder that the channel is closing.
int fr_channel_send_request(fr_channel_t *ch, fr_channel_data_t *cd)
Send a request message into the channel.
int fr_channel_set_recv_reply(fr_channel_t *ch, void *uctx, fr_channel_recv_callback_t recv_reply)
fr_channel_event_t fr_channel_service_message(fr_time_t when, fr_channel_t **p_channel, void const *data, size_t data_size)
Service a control-plane message.
void fr_channel_requestor_uctx_add(fr_channel_t *ch, void *uctx)
Add network-specific data to a channel.
void fr_channel_stats_log(fr_channel_t const *ch, fr_log_t const *log, char const *file, int line)
A full channel, which consists of two ends.
fr_message_t m
the message header
@ FR_CHANNEL_DATA_READY_REQUESTOR
@ FR_CHANNEL_DATA_READY_RESPONDER
void * packet_ctx
Packet specific context for holding client information, and other proto_* specific information that n...
fr_listen_t * listen
for tracking packet transport, etc.
uint32_t priority
Priority of this packet.
Channel information which is added to a message.
char const * parent
e.g. "show module"
char const ** argv
text version of commands
#define FR_CONTROL_ID_INJECT
#define FR_CONTROL_ID_DIRECTORY
#define FR_CONTROL_ID_CHANNEL
#define FR_CONTROL_ID_LISTEN
#define FR_CONTROL_ID_WORKER
#define FR_CONTROL_MAX_SIZE
#define FR_CONTROL_MAX_MESSAGES
static fr_ring_buffer_t * rb
fr_dcursor_eval_t void const * uctx
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_event_fd_insert(...)
fr_event_filter_t
The type of filter to install for an FD.
@ 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.
fr_event_fd_cb_t extend
Additional files were added to a directory.
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.
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
unsigned int fr_heap_index_t
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
#define FR_HEAP_INDEX_INVALID
fr_control_t * fr_control_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_atomic_queue_t *aq)
Create a control-plane signaling path.
int fr_control_callback_add(fr_control_t *c, uint32_t id, void *ctx, fr_control_callback_t callback)
Register a callback for an ID.
int fr_control_message_send(fr_control_t *c, fr_ring_buffer_t *rb, uint32_t id, void *data, size_t data_size)
Send a control-plane message.
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
CONF_SECTION * server_cs
CONF_SECTION of the server.
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.
fr_ring_buffer_t * rb
ring buffer for my control-plane messages
fr_cmd_table_t cmd_network_table[]
size_t fr_network_listen_outstanding(fr_network_t *nr, fr_listen_t *li)
Get the number of outstanding packets.
size_t written
however much we did in a partial write
int fr_network_listen_send_packet(fr_network_t *nr, fr_listen_t *parent, fr_listen_t *li, const uint8_t *buffer, size_t buflen, fr_time_t recv_time, void *packet_ctx)
Send a packet to the worker.
fr_atomic_queue_t * aq_control
atomic queue for control messages sent to me
static int cmd_stats_socket(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info)
int fr_network_listen_add(fr_network_t *nr, fr_listen_t *li)
Add a fr_listen_t to a network.
bool suspended
whether or not we're suspended.
int fr_network_worker_add(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in a different thread.
int fr_network_destroy(fr_network_t *nr)
Stop a network thread in an orderly way.
fr_network_t * nr
O(N) issues in talloc.
static void fr_network_listen_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now)
Handle a network control message callback for a new listener.
static int cmd_stats_self(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info)
fr_log_t const * log
log destination
int fr_network_directory_add(fr_network_t *nr, fr_listen_t *li)
Add a "watch directory" call to a network.
static int _fr_network_free(fr_network_t *nr)
Free any resources associated with a network thread.
static void fr_network_inject_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now)
Handle a network control message callback for a packet sent to a socket.
fr_heap_index_t heap_id
for the sockets_by_num heap
fr_network_t * fr_network_create(TALLOC_CTX *ctx, fr_event_list_t *el, char const *name, fr_log_t const *logger, fr_log_lvl_t lvl, fr_network_config_t const *config)
Create a network.
void fr_network(fr_network_t *nr)
The main network worker function.
fr_message_set_t * ms
message buffers for this socket.
int fr_network_listen_delete(fr_network_t *nr, fr_listen_t *li)
Delete a socket from a network.
int num_blocked
number of blocked workers
static void fr_network_worker_started_callback(void *ctx, void const *data, size_t data_size, fr_time_t now)
char const * name
Network ID for logging.
void fr_network_worker_add_self(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in the same thread.
unsigned int outstanding
number of outstanding packets sent to the worker
static _Thread_local fr_ring_buffer_t * fr_network_rb
static fr_event_update_t const resume_write[]
fr_time_delta_t predicted
predicted processing time for one packet
static int fr_network_pre_event(fr_time_t now, fr_time_delta_t wake, void *uctx)
fr_worker_t * worker
worker pointer
int fr_network_sendto_worker(fr_network_t *nr, fr_listen_t *li, void *packet_ctx, uint8_t const *data, size_t data_len, fr_time_t recv_time)
int fr_network_exit(fr_network_t *nr)
Signal a network thread to exit.
int fr_network_listen_inject(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, fr_time_t recv_time)
Inject a packet for a listener to read.
fr_listen_t * listen
I/O ctx and functions.
int num_sockets
actually a counter...
fr_rb_node_t listen_node
rbtree node for looking up by listener.
static void fr_network_vnode_extend(UNUSED fr_event_list_t *el, int sockfd, int fflags, void *ctx)
Get a notification that a vnode changed.
static void _signal_pipe_read(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Read handler for signal pipe.
static int8_t reply_cmp(void const *one, void const *two)
int num_workers
number of active workers
static int8_t socket_num_cmp(void const *one, void const *two)
int num_pending_workers
number of workers we're waiting to start.
fr_rb_tree_t * sockets
list of sockets we're managing, ordered by the listener
pthread_t thread_id
for self
fr_log_lvl_t lvl
debug log level
int signal_pipe[2]
Pipe for signalling the worker in an orderly way.
fr_channel_data_t * pending
the currently pending partial packet
static int8_t socket_listen_cmp(void const *one, void const *two)
static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, void *ctx)
Write packets to the network.
fr_event_list_t * el
our event list
fr_heap_t * replies
replies from the worker, ordered by priority / origin time
static int fr_network_send_request(fr_network_t *nr, fr_channel_data_t *cd)
Send a message on the "best" channel.
void fr_network_stats_log(fr_network_t const *nr, fr_log_t const *log)
fr_heap_t * waiting
packets waiting to be written
int fr_network_stats(fr_network_t const *nr, int num, uint64_t *stats)
fr_heap_index_t heap_id
workers are in a heap
bool blocked
is this worker blocked?
static void fr_network_read(UNUSED fr_event_list_t *el, int sockfd, UNUSED int flags, void *ctx)
Read a packet from the network.
static bool is_network_thread(fr_network_t const *nr)
fr_rb_node_t num_node
rbtree node for looking up by number.
static void fr_network_error(UNUSED fr_event_list_t *el, UNUSED int sockfd, int flags, int fd_errno, void *ctx)
Handle errors for a socket.
fr_channel_data_t * cd
cached in case of allocation & read error
static int fr_network_listen_add_self(fr_network_t *nr, fr_listen_t *listen)
static void fr_network_suspend(fr_network_t *nr)
size_t leftover
leftover data from a previous read
static void fr_network_post_event(fr_event_list_t *el, fr_time_t now, void *uctx)
fr_network_worker_t * workers[MAX_WORKERS]
each worker
static void fr_network_unsuspend(fr_network_t *nr)
fr_rb_tree_t * sockets_by_num
ordered by number;
fr_network_config_t config
configuration
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
static int8_t waiting_cmp(void const *one, void const *two)
static fr_ring_buffer_t * fr_network_rb_init(void)
Initialise thread local storage.
static int _fr_network_rb_free(void *arg)
static void fr_network_recv_reply(void *ctx, fr_channel_t *ch, fr_channel_data_t *cd)
Callback which handles a message being received on the network side.
int max_workers
maximum number of allowed workers
void fr_network_listen_write(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, void *packet_ctx, fr_time_t request_time)
Inject a packet for a listener to write.
bool exiting
are we exiting?
fr_event_filter_t filter
what type of filter it is
static void fr_network_socket_dead(fr_network_t *nr, fr_network_socket_t *s)
static void fr_network_directory_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now)
Handle a network control message callback for a new "watch directory".
fr_channel_t * channel
channel to the worker
static fr_event_update_t const pause_write[]
static int _network_socket_free(fr_network_socket_t *s)
static void fr_network_channel_callback(void *ctx, void const *data, size_t data_size, fr_time_t now)
Handle a network control message callback for a channel.
static int cmd_socket_list(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info)
fr_time_delta_t cpu_time
how much CPU time this worker has spent
fr_control_t * control
the control plane
bool blocked
is it blocked?
Associate a worker thread with a network thread.
#define RATE_LIMIT_GLOBAL(_log, _fmt,...)
Rate limit messages using a global limiting entry.
int fr_event_post_delete(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Delete a post-event callback from the event list.
void fr_event_service(fr_event_list_t *el)
Service any outstanding timer or file descriptor events.
int fr_event_pre_delete(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
Delete a pre-event callback from the event list.
int fr_event_corral(fr_event_list_t *el, fr_time_t now, bool wait)
Gather outstanding timer and file descriptor events.
int fr_event_post_insert(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Add a post-event callback to the event list.
int fr_event_pre_insert(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
Add a pre-event callback to 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.
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ L_DBG
Only displayed when debugging is enabled.
static fr_event_update_t pause_read[]
static fr_event_update_t resume_read[]
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size)
Create a message set.
int fr_message_done(fr_message_t *m)
Mark a message as done.
fr_message_t * fr_message_localize(TALLOC_CTX *ctx, fr_message_t *m, size_t message_size)
Localize a message by copying it to local storage.
fr_message_t * fr_message_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
fr_message_t * fr_message_alloc(fr_message_set_t *ms, fr_message_t *m, size_t actual_packet_size)
Allocate packet data for a message.
fr_message_t * fr_message_alloc_reserve(fr_message_set_t *ms, fr_message_t *m, size_t actual_packet_size, size_t leftover, size_t reserve_size)
Allocate packet data for a message, and reserve a new message.
A Message set, composed of message headers and ring buffer data.
size_t rb_size
cache-aligned size in the ring buffer
fr_time_t when
when this message was sent
uint8_t * data
pointer to the data in the ring buffer
size_t data_size
size of the data in the ring buffer
fr_message_status_t status
free, used, done, etc.
int fr_nonblock(UNUSED int fd)
static const conf_parser_t config[]
static fr_app_io_t app_io
uint32_t fr_rand(void)
Return a 32-bit random number.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
#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.
int fr_rb_flatten_inorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree)
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
fr_ring_buffer_t * fr_ring_buffer_create(TALLOC_CTX *ctx, size_t size)
Create a ring buffer.
static char buff[sizeof("18446744073709551615")+3]
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#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)
#define fr_time_delta_lt(_a, _b)
#define fr_time_wrap(_time)
#define fr_time_delta_ispos(_a)
static int8_t fr_time_cmp(fr_time_t a, fr_time_t b)
Compare two fr_time_t values.
A time delta, a difference in time measured in nanoseconds.
static fr_event_list_t * el
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)
fr_channel_t * fr_worker_channel_create(fr_worker_t *worker, TALLOC_CTX *ctx, fr_control_t *master)
Create a channel to the worker.
int fr_worker_listen_cancel(fr_worker_t *worker, fr_listen_t const *li)
A worker which takes packets from a master, and processes them.