25 #include <freeradius-devel/bio/bio_priv.h>
26 #include <freeradius-devel/bio/null.h>
27 #include <freeradius-devel/bio/buf.h>
28 #include <freeradius-devel/util/rb.h>
29 #include <freeradius-devel/util/dlist.h>
31 #define _BIO_RETRY_PRIVATE
32 #include <freeradius-devel/bio/retry.h>
127 if (first == my->
partial)
goto cancel_timer;
132 if (first == my->
first)
return 0;
159 item->cancelled =
true;
177 item->packet_ctx = NULL;
180 fr_bio_retry_list_insert_head(&my->free,
item);
221 if (rcode ==
fr_bio_error(IO_WOULD_BLOCK))
return rcode;
230 if ((
size_t) rcode < item->size) {
277 if (rcode <= 0)
return rcode;
321 if (rcode <= 0)
return rcode;
342 if (
item->cancelled) {
349 item->packet_ctx = NULL;
351 fr_bio_retry_list_insert_head(&my->free,
item);
373 if (rcode < 0)
return rcode;
480 if ((
size_t) rcode == size)
return rcode;
485 if (rcode == 0)
return 0;
494 if (rcode ==
fr_bio_error(IO_WOULD_BLOCK))
return rcode;
551 if (rcode == 0)
return;
583 return next->
write(next, packet_ctx, NULL, size);
589 if (fr_bio_retry_list_num_elements(&my->free) == 0) {
601 fr_assert(fr_bio_retry_list_num_elements(&my->free) > 0);
611 rcode = next->
write(next, packet_ctx,
buffer, size);
612 if (rcode <= 0)
return rcode;
617 item = fr_bio_retry_list_pop_head(&my->free);
621 item->retry.config = NULL;
623 item->packet_ctx = packet_ctx;
633 if (!
item->retry.config) {
644 fr_bio_retry_list_insert_head(&my->free,
item);
651 if ((
size_t) rcode < size) {
690 rcode = next->
read(next, packet_ctx,
buffer, size);
691 if (rcode <= 0)
return rcode;
703 item->retry.replies++;
704 if (
item->retry.replies <
item->retry.count)
return 0;
726 item->retry.replies++;
781 if (!
item->retry.replies)
return 0;
803 if (
item->retry.config)
return -1;
820 if (!
item->retry.config)
return NULL;
869 if (!max_saved)
return NULL;
870 if (max_saved > 65536)
return NULL;
873 if (!my)
return NULL;
880 if (!items)
return NULL;
885 fr_bio_retry_list_init(&my->free);
886 for (i = 0; i < max_saved; i++) {
888 fr_bio_retry_list_insert_tail(&my->free, &items[i]);
static int const char char buffer[256]
fr_bio_write_t _CONST write
write to the underlying bio
fr_bio_read_t _CONST read
read from the underlying bio
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
static ssize_t fr_bio_retry_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
const fr_retry_t * fr_bio_retry_entry_info(UNUSED fr_bio_t *bio, fr_bio_retry_entry_t *item)
Allow the callbacks / application to know when things are being retried.
fr_bio_retry_release_t release
fr_bio_t * fr_bio_retry_alloc(TALLOC_CTX *ctx, size_t max_saved, fr_bio_retry_sent_t sent, fr_bio_retry_response_t response, fr_bio_retry_rewrite_t rewrite, fr_bio_retry_release_t release, fr_bio_retry_config_t const *cfg, fr_bio_t *next)
Allocate a fr_bio_retry_t.
int fr_bio_retry_entry_start(UNUSED fr_bio_t *bio, fr_bio_retry_entry_t *item, fr_retry_config_t const *cfg)
Set a per-packet retry config.
static void fr_bio_retry_release(fr_bio_retry_t *my, fr_bio_retry_entry_t *item, fr_bio_retry_release_reason_t reason)
Release an entry back to the free list.
static int fr_bio_retry_destructor(fr_bio_retry_t *my)
Cancel all outstanding packets.
int fr_bio_retry_entry_cancel(fr_bio_t *bio, fr_bio_retry_entry_t *item)
Cancel one item.
struct fr_bio_retry_list_s fr_bio_retry_list_t
ssize_t fr_bio_retry_rewrite(fr_bio_t *bio, fr_bio_retry_entry_t *item, const void *buffer, size_t size)
Resend a packet.
static int fr_bio_retry_write_item(fr_bio_retry_t *my, fr_bio_retry_entry_t *item, fr_time_t now)
Write one item.
static void fr_bio_retry_timer(UNUSED fr_event_list_t *el, fr_time_t now, void *uctx)
Run a timer event.
fr_retry_config_t retry_config
static int fr_bio_retry_write_delayed(fr_bio_retry_t *my, fr_time_t now)
fr_bio_retry_entry_t * partial
for partial writes
static int8_t _entry_cmp(void const *one, void const *two)
fr_bio_retry_response_t response
static ssize_t fr_bio_retry_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write a request, and see if we have a reply.
static ssize_t fr_bio_retry_blocked(fr_bio_retry_t *my, fr_bio_retry_entry_t *item, ssize_t rcode)
The write is blocked.
static ssize_t fr_bio_retry_write_fatal(fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
A previous timer write had a fatal error, so we forbid further writes.
static ssize_t fr_bio_retry_write_partial(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
There's a partial packet written.
fr_bio_retry_entry_t * first
for timers
fr_bio_retry_rewrite_t rewrite
fr_event_timer_t const * ev
static int fr_bio_retry_reset_timer(fr_bio_retry_t *my)
Reset the timer after changing the rb tree.
fr_retry_config_t retry_config
base retry config
void(* fr_bio_retry_release_t)(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, fr_bio_retry_release_reason_t reason)
Callback on release the packet (timeout or have all replies)
fr_retry_t retry
retry timers and counters
fr_bio_retry_release_reason_t
@ FR_BIO_RETRY_WRITE_ERROR
@ FR_BIO_RETRY_FATAL_ERROR
void(* fr_bio_retry_sent_t)(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size, fr_bio_retry_entry_t *retry_ctx)
Callback for when a packet is sent.
ssize_t(* fr_bio_retry_rewrite_t)(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, const void *buffer, size_t size)
bool(* fr_bio_retry_response_t)(fr_bio_t *bio, fr_bio_retry_entry_t **item_p, void *packet_ctx, const void *buffer, size_t size)
Callback on read to see if a packet is a response.
fr_event_list_t * el
event list
void * packet_ctx
packet_ctx from the write() call
bool cancelled
was this item cancelled?
fr_bio_retry_t * my
so we can get to it from the event timer callback
fr_bio_retry_rewrite_t rewrite
per-packet rewrite callback
void * uctx
user-writable context
static void fr_bio_chain(fr_bio_t *first, fr_bio_t *second)
Chain one bio after another.
int fr_bio_buf_alloc(TALLOC_CTX *ctx, fr_bio_buf_t *bio_buf, size_t size)
ssize_t fr_bio_buf_write(fr_bio_buf_t *bio_buf, const void *buffer, size_t size)
uint8_t * start
start of the buffer
static size_t fr_bio_buf_used(fr_bio_buf_t const *bio_buf)
static void fr_bio_buf_reset(fr_bio_buf_t *bio_buf)
uint8_t * read
where in the buffer reads are taken from
static size_t fr_bio_buf_size(fr_bio_buf_t const *bio_buf)
#define FR_DLIST_TYPES(_name)
Define type specific wrapper structs for dlists.
#define FR_DLIST_ENTRY(_name)
Expands to the type name used for the entry wrapper structure.
#define FR_DLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for dlists.
#define fr_event_timer_at(...)
Stores all information relating to an event list.
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
typedef FR_DLIST_HEAD(map_list) map_list_t
Given these are used in so many places, it's more friendly to have a proper type.
void * fr_rb_first(fr_rb_tree_t *tree)
void * fr_rb_remove_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove an entry from the tree, using the node structure, without freeing the data.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
void * fr_rb_last(fr_rb_tree_t *tree)
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
#define fr_time()
Allow us to arbitrarily manipulate time.
static int talloc_const_free(void const *ptr)
Free const'd memory.
static fr_time_t fr_time_add_time_delta(fr_time_t a, fr_time_delta_t b)
static int64_t fr_time_delta_unwrap(fr_time_delta_t 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.
static fr_event_list_t * el
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
fr_time_delta_t irt
Initial transmission time.
fr_time_delta_t mrd
Maximum retransmission duration.
fr_time_t next
when the next timer should be set
#define fr_strerror_const(_msg)