24#include <freeradius-devel/io/listen.h>
25#include <freeradius-devel/io/master.h>
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module.h>
29#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/util/misc.h>
32#include <freeradius-devel/util/syserror.h>
169 talloc_free_children(track);
205 if (ret != 0)
return ret;
252 if (ret != 0)
return ret;
280static int8_t
track_cmp(
void const *one,
void const *two)
297 if (ret != 0)
return ret;
385#define DUP_FIELD(_x) do { if (parent->_x) {c->_x = talloc_strdup(c, parent->_x); if (!c->_x) {goto error;}}} while (0)
386#define COPY_FIELD(_x) c->_x = parent->_x
396 COPY_FIELD(require_message_authenticator_is_set);
441 pthread_mutex_lock(&client->
mutex);
444 pthread_mutex_unlock(&client->
mutex);
449 pthread_mutex_unlock(&client->
mutex);
471 TALLOC_FREE(connection->
client);
519 DEBUG(
"proto_%s - Ignoring connection from client %s - 'max_connections' limit reached.",
521 if (fd >= 0)
close(fd);
530 inst_name = talloc_asprintf(NULL,
"%"PRIu64, thread->
client_id++);
562 MEM(connection->
address = talloc_memdup(connection, address,
sizeof(*address)));
563 (void) talloc_set_name_const(connection->
address,
"fr_io_address_t");
565 connection->
parent = client;
569 memset(connection->
client, 0,
sizeof(*connection->
client));
585 if (
inst->app_io->track_duplicates) {
643 switch (client->
state) {
651 radclient->
active =
false;
671 memcpy(li, thread->
listen,
sizeof(*li));
686 inst->app_io->common.thread_inst_size);
689 inst->app_io->common.name);
709 memcpy(li, thread->
listen,
sizeof(*li));
726 if (
inst->app_io->connection_set(connection->
child, connection->
address) < 0) {
727 DEBUG(
"proto_%s - Failed setting connection for socket.",
inst->app->common.name);
748 struct sockaddr_storage src;
753 DEBUG(
"proto_%s - Failed getting IP address",
inst->app->common.name);
758 if (
inst->app_io->open(connection->
child) < 0) {
759 DEBUG(
"proto_%s - Failed opening connected socket.",
inst->app->common.name);
766 if (connect(fd, (
struct sockaddr *) &src, salen) < 0) {
777 if (
inst->app_io->fd_set(connection->
child, fd) < 0) {
778 DEBUG3(
"Failed setting FD to %s",
inst->app_io->common.name);
784 if (!
inst->app_io->get_name) {
785 connection->
name =
fr_asprintf(connection,
"proto_%s from client %pV port "
786 "%u to server %pV port %u",
787 inst->app->common.name,
793 connection->
name =
inst->app_io->get_name(connection->
child);
807 pthread_mutex_lock(&client->
mutex);
815 pthread_mutex_unlock(&client->
mutex);
816 ERROR(
"proto_%s - Failed inserting connection into tracking table. "
817 "Closing it, and discarding all packets for connection %s.",
818 inst->app_io->common.name, connection->
name);
822 pthread_mutex_unlock(&client->
mutex);
829 connection->
name = talloc_strdup(connection, nak->
name);
831 connection->
el = nak->
el;
835 DEBUG(
"proto_%s - starting connection %s",
inst->app_io->common.name, connection->
name);
837 if (!connection->
nr) {
838 ERROR(
"proto_%s - Failed inserting connection into scheduler. "
839 "Closing it, and diuscarding all packets for connection %s.",
840 inst->app_io->common.name, connection->
name);
841 pthread_mutex_lock(&client->
mutex);
843 pthread_mutex_unlock(&client->
mutex);
846 if (fd >= 0)
close(fd);
885 *
inst = (*connection)->client->inst;
886 if (thread) *thread = NULL;
887 if (child) *child = (*connection)->child;
902 radclient->
secret = radclient->
nas_type = talloc_strdup(radclient,
"");
958 memset(client, 0,
sizeof(*client));
960 client->
state = state;
990 if (
inst->app_io->track_duplicates) {
1002 (void) pthread_mutex_init(&client->
mutex, NULL);
1011 ERROR(
"proto_%s - Failed inserting client %s into tracking table. Discarding client, and all packets for it.",
1039 uint8_t const *packet,
size_t packet_len,
1055 memcpy(my_address, address,
sizeof(*address));
1084 track, packet, packet_len);
1094 if (!old)
goto do_insert;
1118 len = talloc_array_length(old->
packet);
1119 if ((len == talloc_array_length(track->
packet)) &&
1128 DEBUG(
"Ignoring duplicate packet while client %s is still pending dynamic definition",
1219 pending->
track = track;
1277 int value, accept_fd = -1;
1290 if (*leftover)
goto do_read;
1304 if (connection->
dead) {
1305 DEBUG(
"Dead connection %s", connection->
name);
1320 track = pending->
track;
1326 talloc_set_destructor(pending, NULL);
1339 DEBUG3(
"Discarding old packet");
1348 *packet_ctx = track;
1350 recv_time = *recv_time_p = pending->
recv_time;
1359 memcpy(&address, track->
address,
sizeof(address));
1369 }
else if (!connection && (
inst->ipproto == IPPROTO_TCP)) {
1370 struct sockaddr_storage saremote;
1373 salen =
sizeof(saremote);
1380 accept_fd = accept(child->
fd,
1381 (
struct sockaddr *) &saremote, &salen);
1387 if (accept_fd < 0) {
1388 DEBUG(
"proto_%s - failed to accept new socket: %s",
1398#ifdef STATIC_ANALYZER
1399 saremote.ss_family = AF_INET;
1405 if ((saremote.ss_family == AF_INET) || (saremote.ss_family == AF_INET6)) {
1409 salen =
sizeof(saremote);
1414 (void) getsockname(accept_fd, (
struct sockaddr *) &saremote, &salen);
1417 address.
socket.
type = (
inst->ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1429 local_address = &address;
1449 packet_len =
inst->app_io->read(child, (
void **) &local_address, &recv_time,
1450 buffer, buffer_len, leftover);
1451 if (packet_len <= 0) {
1460 if (
inst->app->priority) {
1469 DEBUG2(
"proto_%s - ignoring packet from IP %pV. It is not configured as 'type = ...'",
1487 connection->
paused =
true;
1500 &address.
socket.inet.src_ipaddr.addr, address.
socket.inet.src_ipaddr.prefix);
1504 client = connection->
client;
1510 address = *connection->
address;
1517 if (accept_fd >= 0)
close(accept_fd);
1536 radclient =
inst->app_io->client_find(thread->
child, &address.
socket.inet.src_ipaddr,
inst->ipproto);
1544 radclient->
active =
true;
1546 }
else if (
inst->dynamic_clients) {
1548 if (accept_fd < 0) {
1549 DEBUG(
"proto_%s - ignoring packet from client IP address %pV - "
1550 "too many dynamic clients are defined",
1553 DEBUG(
"proto_%s - ignoring connection attempt from client IP address %pV "
1554 "- too many dynamic clients are defined",
1565 address.
socket.inet.src_ipaddr.prefix);
1567 DEBUG3(
"Source IP %pV is outside of 'allowed' network range",
1575 if (network->
af == AF_UNSPEC) {
1576 DEBUG3(
"Source IP %pV is forbidden by the 'deny' network range",
1590 if (accept_fd < 0) {
1591 DEBUG(
"proto_%s - ignoring packet from unknown client IP address %pV",
1594 DEBUG(
"proto_%s - ignoring connection attempt from unknown client IP address %pV",
1612 if (accept_fd >= 0) {
1635 bool is_dup =
false;
1639 DEBUG(
"Failed tracking packet from client %s - discarding it",
1651 DEBUG(
"Ignoring retransmit from client %s - we are not responding to this request", client->
radclient->
shortname);
1655 if (!track->
reply) {
1657 DEBUG(
"Ignoring retransmit from client %s - we are still processing the request", client->
radclient->
shortname);
1662 nr = connection->
nr;
1708 DEBUG(
"Too many pending packets for client %pV - discarding packet",
1727 DEBUG(
"Client %pV is still being dynamically defined. "
1728 "Caching this packet until the client has been defined",
1754 *packet_ctx = track;
1774 my_connection.
address = &address;
1776 pthread_mutex_lock(&client->
mutex);
1779 pthread_mutex_unlock(&client->
mutex);
1786 DEBUG(
"Discarding packet to NAKed connection %s", connection->
name);
1802 DEBUG(
"Sending packet to connection %s", connection->
name);
1821 buffer, packet_len, recv_time);
1833 bool is_dup =
false;
1841 DEBUG2(
"Received injected packet for an unconnected socket.");
1846 if (priority <= 0) {
1854 buffer, buffer_len, recv_time, &is_dup);
1856 DEBUG2(
"Failed injecting packet to tracking table");
1873 DEBUG2(
"Failed injecting packet due to allocation error");
1891 if (
inst->app_io->open(thread->
child) < 0)
return -1;
1932 if (!
inst->submodule)
return;
1934 if (
inst->app_io->event_list_set) {
1935 inst->app_io->event_list_set(child,
el, nr);
1946 connection->
el =
el;
1947 connection->
nr = nr;
1979 if (client->
ev)
return;
1981 switch (client->
state) {
1987 delay =
inst->idle_timeout;
1995 delay =
inst->nak_lifetime;
2036 connection->
dead =
true;
2078 DEBUG(
"proto_%s - No packets are using unconnected socket %s",
inst->app_io->common.name, connection->
name);
2102 pthread_mutex_lock(&client->
mutex);
2105 pthread_mutex_unlock(&client->
mutex);
2121 DEBUG(
"proto_%s - idle timeout for connection %s",
inst->app_io->common.name, connection->
name);
2133 delay =
inst->idle_timeout;
2147 delay =
inst->check_interval;
2152 ERROR(
"proto_%s - Failed adding timeout for dynamic client %s. It will be permanent!",
2188 DEBUG(
"proto_%s - cleaning up request in %.6fs",
inst->app_io->common.name,
2193 DEBUG(
"proto_%s - Failed adding cleanup_delay for packet. Discarding packet immediately",
2194 inst->app_io->common.name);
2202 DEBUG2(
"TIMER - proto_%s - cleanup delay",
inst->app_io->common.name);
2204 DEBUG2(
"proto_%s - cleaning up",
inst->app_io->common.name);
2245 el = connection->
el;
2266 DEBUG3(
"Suppressing reply as we have a newer packet");
2287 packet_len =
inst->app_io->write(child, track, request_time,
2288 buffer, buffer_len, written);
2289 if (packet_len <= 0) {
2300 if ((
size_t) packet_len < buffer_len) {
2308 if (!
inst->app_io->track_duplicates)
goto setup_timer;
2316 if (!track->
reply) {
2344 if ((buffer_len == 1) && (*
buffer ==
true)) {
2345 DEBUG(
"Request has timed out trying to define a new client. Trying again.");
2354 if (buffer_len == 1) {
2357 if (client->
table) TALLOC_FREE(client->
table);
2373 if (connection && (
inst->ipproto == IPPROTO_UDP)) {
2377 errno = ECONNREFUSED;
2390 fr_assert(buffer_len ==
sizeof(radclient));
2392 memcpy(&radclient,
buffer,
sizeof(radclient));
2403 DEBUG(
"Client IP address %pV IP version does not match the source network %pV of the packet.",
2413 DEBUG(
"Client IP address %pV is not within the prefix with the defined network %pV",
2418 ipaddr = radclient->
ipaddr;
2421 DEBUG(
"Client IP address %pV is not within the defined network %pV.",
2435 if (((radclient->
ipaddr.
af == AF_INET) &&
2437 ((radclient->
ipaddr.
af == AF_INET6) &&
2439 ERROR(
"Cannot define a dynamic client as a network");
2457#define COPY_FIELD(_x) client->radclient->_x = radclient->_x
2458#define DUP_FIELD(_x) client->radclient->_x = talloc_strdup(client->radclient, radclient->_x)
2475 COPY_FIELD(require_message_authenticator_is_set);
2493 talloc_steal(radclient, radclient->
cs);
2520 if (connection->
paused) {
2549 DEBUG(
"proto_%s - cannot use connected sockets as underlying 'transport = %s' does not support it.",
2550 inst->app_io->common.name,
inst->submodule->module->exported->name);
2573 (void) pthread_mutex_init(&client->
mutex, NULL);
2635 if (
inst->app_io->close) {
2638 ret =
inst->app_io->close(child);
2639 if (ret < 0)
return ret;
2645 if (!connection)
return 0;
2651 DEBUG(
"Closing connection %s", connection->
name);
2682 inst->app_io_conf =
inst->submodule->conf;
2683 inst->app_io_instance =
inst->submodule->data;
2691 if (!
inst->app_io->track_duplicates) {
2697 if (!
inst->app_io->track_create) {
2698 cf_log_err(
inst->app_io_conf,
"Internal error: 'track_duplicates' is set, but there is no 'track create' function");
2707 if (
inst->app_io->network_get) {
2708 inst->app_io->network_get(&
inst->ipproto, &
inst->dynamic_clients, &
inst->networks,
inst->app_io_instance);
2711 if ((
inst->ipproto == IPPROTO_TCP) && !
inst->app_io->connection_set) {
2712 cf_log_err(
inst->app_io_conf,
"Missing 'connection set' API for proto_%s",
inst->app_io->common.name);
2719 if (
inst->dynamic_clients) {
2723 cf_log_err(
conf,
"Cannot use 'dynamic_clients = yes' as the virtual server has no 'new client { ... }' section defined.");
2780 num = talloc_array_length(allow);
2783 for (i = 0; i < num; i++) {
2789 if (allow[i].af != af) {
2800 &allow[i].addr, allow[i].prefix);
2820 &allow[i].addr, allow[i].prefix);
2823 fr_strerror_const(
"Entry is completely enclosed inside of a previously defined network.");
2834 &allow[i].addr, allow[i].prefix,
2845 num = talloc_array_length(deny);
2846 if (!num)
return trie;
2852 for (i = 0; i < num; i++) {
2858 if (deny[i].af != af) {
2869 &deny[i].addr, deny[i].prefix);
2880 &deny[i].addr, deny[i].prefix);
2883 "contained within a previous 'allow'", i + 1,
fr_box_ipaddr(deny[i]));
2893 if (network->
af != af) {
2906 &deny[i].addr, deny[i].prefix,
2916 deny[i].
af = AF_UNSPEC;
2932 size_t default_message_size,
size_t num_messages)
2940 if (!
inst->app_io) {
2945 if (!
inst->app_io->common.thread_inst_size) {
2946 fr_strerror_const(
"IO modules MUST set 'thread_inst_size' when using the master IO handler.");
2992 if (
inst->dynamic_clients) {
3016 memcpy(child, li,
sizeof(*child));
3026 inst->app_io->common.thread_inst_size);
3030 inst->app_io->common.name);
3049 if (
inst->app_io->open(child) < 0) {
3050 cf_log_err(
inst->app_io_conf,
"Failed opening %s interface",
inst->app_io->common.name);
3072 ERROR(
"Failed opening %s - that port is already in use by another listener in server %s { ... } - %s",
3117 if (
unlikely(!thread))
return NULL;
3129 address->
socket.inet.src_port = src_port;
3130 address->
socket.inet.dst_port = dst_port;
3132 address->
socket.inet.src_ipaddr = *src_ipaddr;
3133 address->
socket.inet.dst_ipaddr = *dst_ipaddr;
3143 .name =
"radius_master_io",
3147 .default_message_size = 4096,
3148 .track_duplicates =
true,
static int const char char buffer[256]
module_t common
Common fields to all loadable modules.
fr_io_track_create_t track_create
create a tracking structure
bool track_duplicates
track duplicate packets
fr_io_name_t get_name
get the socket name
fr_io_track_cmp_t track_compare
compare two tracking structures
Public structure describing an I/O path for a protocol.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
#define CMP_PREFER_LARGER(_a, _b)
Evaluates to -1 for a > b, and +1 for a < b.
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
A section grouping multiple CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
#define fr_event_filter_update(...)
#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(...)
#define fr_event_timer_in(...)
Callbacks for the FR_EVENT_FILTER_IO filter.
Structure describing a modification to a filter's state.
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
uint32_t fr_hash(void const *data, size_t size)
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
unsigned int fr_heap_index_t
static void * fr_heap_peek(fr_heap_t *h)
Return the item from the top of the heap but don't pop it.
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
#define FR_HEAP_INDEX_INVALID
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
union fr_ipaddr_t::@130 addr
fr_socket_t socket
src/dst ip and port.
fr_client_t const * radclient
old-style client definition
size_t num_messages
for the message ring buffer
char const * name
printable name for this socket - set by open
bool track_duplicates
do we track duplicate packets?
fr_socket_t * app_io_addr
for tracking duplicate sockets
void const * app_instance
size_t default_message_size
copied from app_io, but may be changed
bool connected
is this for a connected socket?
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
int fd
file descriptor for this socket - set by open
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_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.
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
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.
char const * server
Name of the virtual server client is associated with.
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
char const * secret
Secret PSK.
bool active
for dynamic clients
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
char const * nas_type
Type of client (arbitrary).
int proto
Protocol number.
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
bool dynamic
Whether the client was dynamically defined.
char const * longname
Client identifier.
fr_socket_limit_t limit
Connections per client (TCP clients only).
char const * shortname
Client nickname.
bool use_connected
do we use connected sockets for this client
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Describes a host allowed to send packets to the server.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Stores all information relating to an event list.
fr_listen_t * child
The child (app_io) IO path.
fr_network_t * nr
network for this connection
static int8_t alive_client_cmp(void const *one, void const *two)
bool in_trie
is the client in the trie?
bool paused
event filter doesn't like resuming something that isn't paused
bool in_parent_hash
for tracking thread issues
static fr_client_t * radclient_clone(TALLOC_CTX *ctx, fr_client_t const *parent)
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)
Implement 99% of the read routines.
int packets
number of packets using this connection
static void client_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
uint32_t num_pending_packets
number of pending packets
static int track_dedup_free(fr_io_track_t *track)
fr_rb_tree_t * table
tracking table for packets
static int8_t pending_packet_cmp(void const *one, void const *two)
fr_heap_t * pending_clients
heap of pending clients
static fr_io_track_t * fr_io_track_add(fr_io_client_t *client, fr_io_address_t *address, uint8_t const *packet, size_t packet_len, fr_time_t recv_time, bool *is_dup)
bool ready_to_delete
are we ready to delete this client?
static fr_io_pending_packet_t * fr_io_pending_alloc(fr_io_client_t *client, uint8_t const *buffer, size_t packet_len, fr_io_track_t *track, int priority)
static int _client_live_free(fr_io_client_t *client)
fr_heap_index_t pending_id
for pending clients
static int pending_free(fr_io_pending_packet_t *pending)
bool use_connected
does this client allow connected sub-sockets?
fr_io_client_t * client
our local client (pending or connected).
static int track_free(fr_io_track_t *track)
fr_app_io_t fr_master_app_io
fr_listen_t * listen
The master IO path.
static int8_t pending_client_cmp(void const *one, void const *two)
fr_io_track_t * fr_master_io_track_alloc(fr_listen_t *li, fr_client_t *radclient, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
fr_io_address_t * address
full information about the connection.
static int8_t address_cmp(void const *one, void const *two)
fr_event_timer_t const * ev
when we clean up the client
fr_listen_t * child
child listener (app_io) for this socket
fr_listen_t * listen
master listener for this socket
static void packet_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
fr_network_t * nr
network for the master socket
fr_trie_t * fr_master_io_network(TALLOC_CTX *ctx, int af, fr_ipaddr_t *allow, fr_ipaddr_t *deny)
Create a trie from arrays of allow / deny IP addresses.
static fr_io_pending_packet_t * pending_packet_pop(fr_io_thread_t *thread)
fr_ipaddr_t network
network for dynamic clients
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new socket.
static int mod_open(fr_listen_t *li)
Open a new listener.
pthread_mutex_t mutex
for parent / child signaling
static fr_io_client_t * client_alloc(TALLOC_CTX *ctx, fr_io_client_state_t state, fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_client_t *radclient, fr_ipaddr_t const *network)
fr_io_instance_t const * inst
parent instance for master IO handler
fr_trie_t * trie
trie of clients
fr_io_client_state_t
Client states.
@ PR_CLIENT_DYNAMIC
dynamically defined client
@ PR_CLIENT_CONNECTED
dynamically defined client in a connected socket
@ PR_CLIENT_PENDING
dynamic client pending definition
@ PR_CLIENT_NAK
negative cache entry
@ PR_CLIENT_STATIC
static / global clients
static void get_inst(fr_listen_t *li, fr_io_instance_t const **inst, fr_io_thread_t **thread, fr_io_connection_t **connection, fr_listen_t **child)
static fr_event_update_t pause_read[]
static int8_t track_connected_cmp(void const *one, void const *two)
fr_heap_t * alive_clients
heap of active clients
fr_schedule_t * sc
the scheduler
static fr_io_connection_t * fr_io_connection_alloc(fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_io_client_t *client, int fd, fr_io_address_t *address, fr_io_connection_t *nak)
Create a new connection.
fr_hash_table_t * addresses
list of src/dst addresses used by this client
int fr_master_io_listen(fr_io_instance_t *inst, fr_schedule_t *sc, size_t default_message_size, size_t num_messages)
static int connection_free(fr_io_connection_t *connection)
int fr_io_listen_free(fr_listen_t *li)
char const * name
taken from proto_FOO_TRANSPORT
fr_heap_index_t alive_id
for all clients
fr_event_list_t * el
event list for this connection
fr_io_client_state_t state
state of this client
int packets
number of packets using this client
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)
bool dead
roundabout way to get the network side to close a socket
fr_event_list_t * el
event list, for the master socket.
uint64_t client_id
Unique client identifier.
static char const * mod_name(fr_listen_t *li)
module_instance_t * mi
for submodule
static int _client_free(fr_io_client_t *client)
static int mod_close(fr_listen_t *li)
Close the socket.
static uint32_t connection_hash(void const *ctx)
fr_io_connection_t * connection
parent connection
fr_heap_t * pending
pending packets for this client
static int count_connections(UNUSED uint8_t const *key, UNUSED size_t keylen, void *data, void *ctx)
Count the number of connections used by active clients.
static int8_t connection_cmp(void const *one, void const *two)
static int8_t track_cmp(void const *one, void const *two)
fr_hash_table_t * ht
for tracking connected sockets
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_client_t * radclient
old-style definition of this client
fr_ipaddr_t src_ipaddr
packets come from this address
static fr_event_update_t resume_read[]
uint32_t num_connections
number of dynamic connections
fr_io_client_t * parent
points to the parent client.
static fr_client_t * radclient_alloc(TALLOC_CTX *ctx, int ipproto, fr_io_address_t *address)
static int mod_inject(fr_listen_t *li, uint8_t const *buffer, size_t buffer_len, fr_time_t recv_time)
Inject a packet to a connection.
Client definitions for master IO.
uint8_t * reply
reply packet (if any)
fr_event_timer_t const * ev
when we clean up this tracking entry
int packets
number of packets using this entry
fr_time_t dynamic
timestamp for packet doing dynamic client definition
void * app_io_instance
Easy access to the app_io instance.
fr_app_io_t const * app_io
Easy access to the app_io handle.
fr_io_address_t const * address
of this packet.. shared between multiple packets
bool do_not_respond
don't respond
bool discard
whether or not we discard the packet
fr_time_t timestamp
when this packet was received
bool finished
are we finished the request?
uint8_t * packet
really a tracking structure, not a packet
size_t reply_len
length of reply, or 1 for "do not reply"
fr_io_client_t * client
client handling this packet.
fr_time_t expires
when this packet expires
int fr_nonblock(UNUSED int fd)
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
#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.
The main red black tree structure.
static unsigned int hash(char const *username, unsigned int tablesize)
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_instantiate_t instantiate
Callback to allow the module to register any per-instance resources like sockets and file handles.
@ MODULE_INSTANCE_BOOTSTRAPPED
Module instance has been bootstrapped, but not yet instantiated.
size_t thread_inst_size
Size of the module's thread-specific instance data.
fr_time_delta_t idle_timeout
static const uchar sc[16]
module_list_type_t const module_list_type_thread_local
Callbacks for a thread local list.
void module_list_mask_set(module_list_t *ml, module_instance_state_t mask)
Set a new bootstrap/instantiate state for a list.
module_instance_t * module_instance_copy(module_list_t *dst, module_instance_t const *src, char const *inst_name)
Duplicate a module instance, placing it in a new module list.
module_list_t * module_list_alloc(TALLOC_CTX *ctx, module_list_type_t const *type, char const *name, bool write_protect)
Allocate a new module list.
int module_thread_instantiate(TALLOC_CTX *ctx, module_instance_t *mi, fr_event_list_t *el)
Allocate thread-local instance data for a module.
int module_instantiate(module_instance_t *instance)
Manually complete module setup by calling its instantiate function.
int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf)
Covert a CONF_SECTION into parsed module instance data.
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_get_type_abort_const
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
static int talloc_const_free(void const *ptr)
Free const'd memory.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
#define fr_time_delta_lt(_a, _b)
static int64_t fr_time_unwrap(fr_time_t time)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_wrap(_time)
#define fr_time_wrap(_time)
#define fr_time_delta_ispos(_a)
#define fr_time_eq(_a, _b)
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_neq(_a, _b)
A time delta, a difference in time measured in nanoseconds.
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
static fr_event_list_t * el
int fd
File descriptor if this is a live socket.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define fr_box_ipaddr(_val)
#define fr_box_time_delta(_val)
bool listen_record(fr_listen_t *li)
Record that we're listening on a particular IP / port.
fr_listen_t * listen_find_any(fr_listen_t *li)
See if another global listener is using a particular IP / port.