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;
280 static 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
438 pthread_mutex_lock(&client->
mutex);
441 pthread_mutex_unlock(&client->
mutex);
446 pthread_mutex_unlock(&client->
mutex);
468 TALLOC_FREE(connection->
client);
516 DEBUG(
"proto_%s - Ignoring connection from client %s - 'max_connections' limit reached.",
518 if (fd >= 0)
close(fd);
527 inst_name = talloc_asprintf(NULL,
"%"PRIu64, thread->
client_id++);
559 MEM(connection->
address = talloc_memdup(connection, address,
sizeof(*address)));
560 (void) talloc_set_name_const(connection->
address,
"fr_io_address_t");
562 connection->
parent = client;
566 memset(connection->
client, 0,
sizeof(*connection->
client));
582 if (
inst->app_io->track_duplicates) {
640 switch (client->
state) {
648 radclient->
active =
false;
668 memcpy(li, thread->
listen,
sizeof(*li));
683 inst->app_io->common.thread_inst_size);
686 inst->app_io->common.name);
706 memcpy(li, thread->
listen,
sizeof(*li));
723 if (
inst->app_io->connection_set(connection->
child, connection->
address) < 0) {
724 DEBUG(
"proto_%s - Failed setting connection for socket.",
inst->app->common.name);
745 struct sockaddr_storage src;
750 DEBUG(
"proto_%s - Failed getting IP address",
inst->app->common.name);
755 if (
inst->app_io->open(connection->
child) < 0) {
756 DEBUG(
"proto_%s - Failed opening connected socket.",
inst->app->common.name);
763 if (connect(fd, (
struct sockaddr *) &src, salen) < 0) {
774 if (
inst->app_io->fd_set(connection->
child, fd) < 0) {
775 DEBUG3(
"Failed setting FD to %s",
inst->app_io->common.name);
781 if (!
inst->app_io->get_name) {
782 connection->
name =
fr_asprintf(connection,
"proto_%s from client %pV port "
783 "%u to server %pV port %u",
784 inst->app->common.name,
790 connection->
name =
inst->app_io->get_name(connection->
child);
804 pthread_mutex_lock(&client->
mutex);
812 pthread_mutex_unlock(&client->
mutex);
813 ERROR(
"proto_%s - Failed inserting connection into tracking table. "
814 "Closing it, and discarding all packets for connection %s.",
815 inst->app_io->common.name, connection->
name);
819 pthread_mutex_unlock(&client->
mutex);
826 connection->
name = talloc_strdup(connection, nak->
name);
828 connection->
el = nak->
el;
832 DEBUG(
"proto_%s - starting connection %s",
inst->app_io->common.name, connection->
name);
834 if (!connection->
nr) {
835 ERROR(
"proto_%s - Failed inserting connection into scheduler. "
836 "Closing it, and diuscarding all packets for connection %s.",
837 inst->app_io->common.name, connection->
name);
838 pthread_mutex_lock(&client->
mutex);
840 pthread_mutex_unlock(&client->
mutex);
843 if (fd >= 0)
close(fd);
882 *
inst = (*connection)->client->inst;
883 if (thread) *thread = NULL;
884 if (child) *child = (*connection)->child;
899 radclient->
secret = radclient->
nas_type = talloc_strdup(radclient,
"");
949 memset(client, 0,
sizeof(*client));
951 client->
state = state;
981 if (
inst->app_io->track_duplicates) {
993 (void) pthread_mutex_init(&client->
mutex, NULL);
1002 ERROR(
"proto_%s - Failed inserting client %s into tracking table. Discarding client, and all packets for it.",
1030 uint8_t const *packet,
size_t packet_len,
1046 memcpy(my_address, address,
sizeof(*address));
1075 track, packet, packet_len);
1085 if (!old)
goto do_insert;
1109 len = talloc_array_length(old->
packet);
1110 if ((len == talloc_array_length(track->
packet)) &&
1119 DEBUG(
"Ignoring duplicate packet while client %s is still pending dynamic definition",
1210 pending->
track = track;
1268 int value, accept_fd = -1;
1281 if (*leftover)
goto do_read;
1295 if (connection->
dead) {
1296 DEBUG(
"Dead connection %s", connection->
name);
1311 track = pending->
track;
1317 talloc_set_destructor(pending, NULL);
1330 DEBUG3(
"Discarding old packet");
1339 *packet_ctx = track;
1341 recv_time = *recv_time_p = pending->
recv_time;
1350 memcpy(&address, track->
address,
sizeof(address));
1360 }
else if (!connection && (
inst->ipproto == IPPROTO_TCP)) {
1361 struct sockaddr_storage saremote;
1364 salen =
sizeof(saremote);
1371 accept_fd = accept(child->
fd,
1372 (
struct sockaddr *) &saremote, &salen);
1378 if (accept_fd < 0) {
1379 DEBUG(
"proto_%s - failed to accept new socket: %s",
1389 #ifdef STATIC_ANALYZER
1390 saremote.ss_family = AF_INET;
1396 if ((saremote.ss_family == AF_INET) || (saremote.ss_family == AF_INET6)) {
1400 salen =
sizeof(saremote);
1405 (void) getsockname(accept_fd, (
struct sockaddr *) &saremote, &salen);
1408 address.
socket.
type = (
inst->ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1420 local_address = &address;
1440 packet_len =
inst->app_io->read(child, (
void **) &local_address, &recv_time,
1441 buffer, buffer_len, leftover);
1442 if (packet_len <= 0) {
1451 if (
inst->app->priority) {
1460 DEBUG2(
"proto_%s - ignoring packet from IP %pV. It is not configured as 'type = ...'",
1478 connection->
paused =
true;
1491 &address.
socket.inet.src_ipaddr.addr, address.
socket.inet.src_ipaddr.prefix);
1495 client = connection->
client;
1501 address = *connection->
address;
1508 if (accept_fd >= 0)
close(accept_fd);
1527 radclient =
inst->app_io->client_find(thread->
child, &address.
socket.inet.src_ipaddr,
inst->ipproto);
1535 radclient->
active =
true;
1537 }
else if (
inst->dynamic_clients) {
1539 if (accept_fd < 0) {
1540 DEBUG(
"proto_%s - ignoring packet from client IP address %pV - "
1541 "too many dynamic clients are defined",
1544 DEBUG(
"proto_%s - ignoring connection attempt from client IP address %pV "
1545 "- too many dynamic clients are defined",
1556 address.
socket.inet.src_ipaddr.prefix);
1558 DEBUG3(
"Source IP %pV is outside of 'allowed' network range",
1566 if (network->
af == AF_UNSPEC) {
1567 DEBUG3(
"Source IP %pV is forbidden by the 'deny' network range",
1581 if (accept_fd < 0) {
1582 DEBUG(
"proto_%s - ignoring packet from unknown client IP address %pV",
1585 DEBUG(
"proto_%s - ignoring connection attempt from unknown client IP address %pV",
1603 if (accept_fd >= 0) {
1626 bool is_dup =
false;
1630 DEBUG(
"Failed tracking packet from client %s - discarding it",
1642 DEBUG(
"Ignoring retransmit from client %s - we are not responding to this request", client->
radclient->
shortname);
1646 if (!track->
reply) {
1648 DEBUG(
"Ignoring retransmit from client %s - we are still processing the request", client->
radclient->
shortname);
1653 nr = connection->
nr;
1699 DEBUG(
"Too many pending packets for client %pV - discarding packet",
1718 DEBUG(
"Client %pV is still being dynamically defined. "
1719 "Caching this packet until the client has been defined",
1745 *packet_ctx = track;
1765 my_connection.
address = &address;
1767 pthread_mutex_lock(&client->
mutex);
1770 pthread_mutex_unlock(&client->
mutex);
1777 DEBUG(
"Discarding packet to NAKed connection %s", connection->
name);
1793 DEBUG(
"Sending packet to connection %s", connection->
name);
1812 buffer, packet_len, recv_time);
1824 bool is_dup =
false;
1832 DEBUG2(
"Received injected packet for an unconnected socket.");
1837 if (priority <= 0) {
1845 buffer, buffer_len, recv_time, &is_dup);
1847 DEBUG2(
"Failed injecting packet to tracking table");
1864 DEBUG2(
"Failed injecting packet due to allocation error");
1882 if (
inst->app_io->open(thread->
child) < 0)
return -1;
1923 if (!
inst->submodule)
return;
1925 if (
inst->app_io->event_list_set) {
1926 inst->app_io->event_list_set(child,
el, nr);
1937 connection->
el =
el;
1938 connection->
nr = nr;
1970 if (client->
ev)
return;
1974 switch (client->
state) {
1980 delay =
inst->idle_timeout;
1988 delay =
inst->nak_lifetime;
2027 connection->
dead =
true;
2069 DEBUG(
"proto_%s - No packets are using unconnected socket %s",
inst->app_io->common.name, connection->
name);
2093 pthread_mutex_lock(&client->
mutex);
2096 pthread_mutex_unlock(&client->
mutex);
2112 DEBUG(
"proto_%s - idle timeout for connection %s",
inst->app_io->common.name, connection->
name);
2124 delay =
inst->idle_timeout;
2138 delay =
inst->check_interval;
2143 ERROR(
"proto_%s - Failed adding timeout for dynamic client %s. It will be permanent!",
2179 DEBUG(
"proto_%s - cleaning up request in %.6fs",
inst->app_io->common.name,
2184 DEBUG(
"proto_%s - Failed adding cleanup_delay for packet. Discarding packet immediately",
2185 inst->app_io->common.name);
2193 DEBUG2(
"TIMER - proto_%s - cleanup delay",
inst->app_io->common.name);
2195 DEBUG2(
"proto_%s - cleaning up",
inst->app_io->common.name);
2236 el = connection->
el;
2257 DEBUG3(
"Suppressing reply as we have a newer packet");
2278 packet_len =
inst->app_io->write(child, track, request_time,
2279 buffer, buffer_len, written);
2280 if (packet_len <= 0) {
2291 if ((
size_t) packet_len < buffer_len) {
2299 if (!
inst->app_io->track_duplicates)
goto setup_timer;
2307 if (!track->
reply) {
2335 if ((buffer_len == 1) && (*
buffer ==
true)) {
2336 DEBUG(
"Request has timed out trying to define a new client. Trying again.");
2345 if (buffer_len == 1) {
2348 if (client->
table) TALLOC_FREE(client->
table);
2364 if (connection && (
inst->ipproto == IPPROTO_UDP)) {
2368 errno = ECONNREFUSED;
2381 fr_assert(buffer_len ==
sizeof(radclient));
2383 memcpy(&radclient,
buffer,
sizeof(radclient));
2394 DEBUG(
"Client IP address %pV IP version does not match the source network %pV of the packet.",
2404 DEBUG(
"Client IP address %pV is not within the prefix with the defined network %pV",
2409 ipaddr = radclient->
ipaddr;
2412 DEBUG(
"Client IP address %pV is not within the defined network %pV.",
2426 if (((radclient->
ipaddr.
af == AF_INET) &&
2428 ((radclient->
ipaddr.
af == AF_INET6) &&
2430 ERROR(
"Cannot define a dynamic client as a network");
2448 #define COPY_FIELD(_x) client->radclient->_x = radclient->_x
2449 #define DUP_FIELD(_x) client->radclient->_x = talloc_strdup(client->radclient, radclient->_x)
2482 talloc_steal(radclient, radclient->
cs);
2496 radclient->
active =
true;
2511 if (connection->
paused) {
2526 DEBUG(
"proto_%s - cannot use connected sockets as underlying 'transport = %s' does not support it.",
2527 inst->app_io->common.name,
inst->submodule->module->exported->name);
2550 (void) pthread_mutex_init(&client->
mutex, NULL);
2612 if (
inst->app_io->close) {
2615 ret =
inst->app_io->close(child);
2616 if (ret < 0)
return ret;
2622 if (!connection)
return 0;
2628 DEBUG(
"Closing connection %s", connection->
name);
2659 inst->app_io_conf =
inst->submodule->conf;
2660 inst->app_io_instance =
inst->submodule->data;
2668 if (!
inst->app_io->track_duplicates) {
2674 if (!
inst->app_io->track_create) {
2675 cf_log_err(
inst->app_io_conf,
"Internal error: 'track_duplicates' is set, but there is no 'track create' function");
2684 if (
inst->app_io->network_get) {
2685 inst->app_io->network_get(&
inst->ipproto, &
inst->dynamic_clients, &
inst->networks,
inst->app_io_instance);
2688 if ((
inst->ipproto == IPPROTO_TCP) && !
inst->app_io->connection_set) {
2689 cf_log_err(
inst->app_io_conf,
"Missing 'connection set' API for proto_%s",
inst->app_io->common.name);
2696 if (
inst->dynamic_clients) {
2700 cf_log_err(
conf,
"Cannot use 'dynamic_clients = yes' as the virtual server has no 'new client { ... }' section defined.");
2705 cf_log_err(
conf,
"Cannot use 'dynamic_clients = yes' as the virtual server has no 'add client { ... }' section defined.");
2710 cf_log_err(
conf,
"Cannot use 'dynamic_clients = yes' as the virtual server has no 'deny client { ... }' section defined.");
2759 num = talloc_array_length(allow);
2762 for (i = 0; i < num; i++) {
2768 if (allow[i].af != af) {
2779 &allow[i].addr, allow[i].prefix);
2799 &allow[i].addr, allow[i].prefix);
2802 fr_strerror_const(
"Entry is completely enclosed inside of a previously defined network.");
2813 &allow[i].addr, allow[i].prefix,
2824 num = talloc_array_length(deny);
2825 if (!num)
return trie;
2831 for (i = 0; i < num; i++) {
2837 if (deny[i].af != af) {
2848 &deny[i].addr, deny[i].prefix);
2859 &deny[i].addr, deny[i].prefix);
2862 "contained within a previous 'allow'", i + 1,
fr_box_ipaddr(deny[i]));
2872 if (network->
af != af) {
2885 &deny[i].addr, deny[i].prefix,
2895 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.");
3015 memcpy(child, li,
sizeof(*child));
3025 inst->app_io->common.thread_inst_size);
3029 inst->app_io->common.name);
3048 if (
inst->app_io->open(child) < 0) {
3049 cf_log_err(
inst->app_io_conf,
"Failed opening %s interface",
inst->app_io->common.name);
3071 ERROR(
"Failed opening %s - that port is already in use by another listener in server %s { ... } - %s",
3116 if (
unlikely(!thread))
return NULL;
3128 address->
socket.inet.src_port = src_port;
3129 address->
socket.inet.dst_port = dst_port;
3131 address->
socket.inet.src_ipaddr = *src_ipaddr;
3132 address->
socket.inet.dst_ipaddr = *dst_ipaddr;
3142 .name =
"radius_master_io",
3146 .default_message_size = 4096,
3147 .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.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
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.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define cf_log_err(_cf, _fmt,...)
fr_dcursor_eval_t void const * uctx
#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.
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
uint32_t fr_hash(void const *data, size_t size)
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
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.
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 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)
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)
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
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)
bool ready_to_delete
are we ready to delete this client?
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_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
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_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.
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
fr_io_instance_t const * inst
parent instance for master IO handler
static fr_client_t * radclient_clone(TALLOC_CTX *ctx, fr_client_t const *parent)
fr_trie_t * trie
trie of clients
static char const * mod_name(fr_listen_t *li)
static int _thread_io_free(fr_io_thread_t *thread)
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_client_t * radclient_alloc(TALLOC_CTX *ctx, int ipproto, fr_io_address_t *address)
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 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)
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
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)
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)
static fr_io_pending_packet_t * pending_packet_pop(fr_io_thread_t *thread)
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.
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 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.
static char const * proto(int id, int porttype)
#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)
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)
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_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_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_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.
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.
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.
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.
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.
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
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.
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
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.
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.
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)
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.