}
}
-static void client_retry_log(UNUSED fr_bio_packet_t *client, fr_packet_t *packet)
+static void client_packet_retry_log(UNUSED fr_bio_packet_t *client, fr_packet_t *packet)
{
rc_request_t *request = packet->uctx;
fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
}
-static void client_release(fr_bio_packet_t *client, fr_packet_t *packet)
+static void client_packet_release(fr_bio_packet_t *client, fr_packet_t *packet)
{
rc_request_t *request = packet->uctx;
}
}
-static void client_connect(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
+static int client_bio_activate(fr_bio_packet_t *client)
{
- int rcode;
- fr_bio_packet_t *client = uctx;
+ fr_radius_client_bio_info_t const *info;
- rcode = fr_radius_client_bio_connect(client);
- if (rcode < 0) {
- /*
- * We may need to try again. If so, do that.
- */
- if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return;
+ info = fr_radius_client_bio_info(client);
- ERROR("Failed connecting socket: %s", fr_strerror());
- fr_exit_now(1);
- }
-
- if (fr_event_fd_insert(autofree, NULL, el, fd, client_read, client_write, client_error, client) < 0) {
+ if (fr_event_fd_insert(autofree, NULL, info->retry_info->el, info->fd_info->socket.fd,
+ client_read, client_write, client_error, client) < 0) {
fr_perror("radclient");
fr_exit_now(1);
}
+
+ return 0;
}
* paused or resumed when the socket becomes writeable.
*/
client_config.packet_cb_cfg = (fr_bio_packet_cb_funcs_t) {
- .write_blocked = client_bio_write_pause,
- .write_resume = client_bio_write_resume,
+ .activate = client_bio_activate,
+
+ .write_blocked = client_bio_write_pause,
+ .write_resume = client_bio_write_resume,
- .retry = (fr_debug_lvl > 0) ? client_retry_log : NULL,
- .release = client_release,
+ .retry = (fr_debug_lvl > 0) ? client_packet_retry_log : NULL,
+ .release = client_packet_release,
};
/*
* Once the connect() passes, we start reading from the request list, and processing packets.
*/
if (fr_event_fd_insert(autofree, NULL, client_config.retry_cfg.el, client_info->fd_info->socket.fd, NULL,
- client_connect, client_error, client_bio) < 0) {
+ fr_radius_client_bio_connect, client_error, client_bio) < 0) {
fr_perror("radclient");
fr_exit_now(1);
}
typedef int (*fr_bio_packet_io_t)(fr_bio_packet_t *bio);
typedef struct {
+ fr_bio_packet_io_t activate;
+
fr_bio_packet_io_t read_blocked;
fr_bio_packet_io_t write_blocked;
struct fr_bio_retry_s {
FR_BIO_COMMON;
- fr_event_list_t *el;
fr_rb_tree_t timer_tree;
fr_rb_tree_t expiry_tree;
/*
* Update the timer. This should never fail.
*/
- if (fr_event_timer_at(my, my->el, &my->ev, first->retry.end, fr_bio_retry_expiry_timer, my) < 0) return -1;
+ if (fr_event_timer_at(my, my->info.el, &my->ev, first->retry.end, fr_bio_retry_expiry_timer, my) < 0) return -1;
my->timer_item = first;
return 0;
/*
* Update the timer. This should never fail.
*/
- if (fr_event_timer_at(my, my->el, &my->ev, first->retry.next, fr_bio_retry_timer, my) < 0) return -1;
+ if (fr_event_timer_at(my, my->info.el, &my->ev, first->retry.next, fr_bio_retry_timer, my) < 0) return -1;
my->timer_item = first;
return 0;
my->response = response;
my->release = release;
- my->el = cfg->el;
my->info.last_idle = fr_time();
+ my->info.el = cfg->el;
+ my->info.cfg = cfg;
+
my->retry_config = cfg->retry_config;
my->bio.write = fr_bio_retry_write;
my->bio.read = fr_bio_retry_read;
-
fr_bio_chain(&my->bio, next);
talloc_set_destructor(my, fr_bio_retry_destructor);
} fr_bio_retry_config_t;
typedef struct {
+ fr_event_list_t *el; //!< event list
+
fr_time_t mrs_time; //!< Most recent sent time which had a reply.
fr_time_t last_reply; //!< When we last received a reply.
fr_time_t first_sent; //!< first time we sent a packet since going idle
fr_time_t last_idle; //!< last time we had nothing to do
bool write_blocked; //!< are writes blocked?
+
+ fr_bio_retry_config_t const *cfg; //!< so we know what was asked
} fr_bio_retry_info_t;
typedef struct fr_bio_retry_entry_s fr_bio_retry_entry_t;
static void radius_client_retry_release(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED fr_bio_retry_release_reason_t reason);
static ssize_t radius_client_retry(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED const void *buffer, NDEBUG_UNUSED size_t size);
-static int fr_radius_client_bio_write_blocked(fr_bio_t *bio);
-static int fr_radius_client_bio_write_resume(fr_bio_t *bio);
-
-static const fr_bio_cb_funcs_t client_bio_cb_funcs = {
- .write_blocked = fr_radius_client_bio_write_blocked,
- .write_resume = fr_radius_client_bio_write_resume,
-};
-
fr_bio_packet_t *fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
{
fr_assert(fd_cfg->type == FR_BIO_FD_CONNECTED);
/*
* Inform all BIOs about the write pause / resume callbacks
+ *
+ * @todo - these callbacks are set AFTER the BIOs have been initialized, so the activate()
+ * callback is never set, and therefore is never run. We should add all of the callbacks to the
+ * various bio "cfg" data structures.
*/
- fr_radius_client_bio_cb_set(bio, cfg->packet_cb_cfg);
+ fr_radius_client_bio_cb_set(&my->common, &cfg->packet_cb_cfg);
/*
* Set up the connected status.
return fr_radius_code_id_force(my->codes, code, id);
}
-
-/** Try to connect a socket.
- *
- * Calls fr_bio_fd_connect()
- *
- * @param bio the packet bio
- * @return
- * - 0 for "connected, can continue"
- * - fr_bio_error(IO_WOULD_BLOCK) for "not yet connected, please try again"
- * - <0 for other fr_bio_error()
+/** Callback for when the FD is activated, i.e. connected.
*
*/
-int fr_radius_client_bio_connect(fr_bio_packet_t *bio)
+static int fr_radius_client_bio_activate(fr_bio_t *bio)
{
- int rcode;
- fr_radius_client_fd_bio_t *my = talloc_get_type_abort(bio, fr_radius_client_fd_bio_t);
+ fr_radius_client_fd_bio_t *my = bio->uctx;
- if (my->info.connected) return 0;
+ fr_assert(!my->info.connected);
- switch (my->info.fd_info->type) {
- default:
- fr_strerror_const("Invalid RADIUS client bio for connect");
- return fr_bio_error(GENERIC);
+ my->info.connected = true;
- case FR_BIO_FD_UNCONNECTED:
- return 0;
+ fr_assert(0);
- case FR_BIO_FD_CONNECTED:
- break;
- }
- switch(my->info.fd_info->state) {
- case FR_BIO_FD_STATE_INVALID:
- fr_strerror_const("Invalid RADIUS client bio state");
- return fr_bio_error(GENERIC);
+ return 0;
+}
- case FR_BIO_FD_STATE_CLOSED:
- fr_strerror_const("RADIUS client bio is closed");
- return fr_bio_error(GENERIC);
+void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx)
+{
+ fr_radius_client_fd_bio_t *my = talloc_get_type_abort(uctx, fr_radius_client_fd_bio_t);
+ int rcode;
- case FR_BIO_FD_STATE_OPEN:
- return 0;
+ fr_assert(my->common.cb.activate);
+ fr_assert(my->info.retry_info->el == el);
+ fr_assert(my->info.fd_info->socket.fd == fd);
- case FR_BIO_FD_STATE_CONNECTING:
- break;
- }
+ /*
+ * The socket is already connected, go activate it. This happens when the FD bio opens an
+ * unconnected socket. It calls our activation routine before the application has a chance to
+ * call our connect routine.
+ */
+ if (my->info.connected) goto activate;
+
+ fr_assert(my->info.fd_info->type == FR_BIO_FD_CONNECTED);
+ fr_assert(my->info.fd_info->state == FR_BIO_FD_STATE_CONNECTING);
/*
* Try to connect it.
*/
rcode = fr_bio_fd_connect(my->fd);
+ fr_assert(rcode >= 0);
- my->info.connected = (rcode == 0);
- return rcode;
+ my->info.connected = true;
+
+activate:
+ (void) my->common.cb.activate(&my->common);
}
+
+
/** Callback for when the writes are blocked.
*
*/
fr_assert((cb->write_blocked != NULL) == (cb->write_resume != NULL));
fr_assert((cb->read_blocked != NULL) == (cb->read_resume != NULL));
+ bio_cb.activate = fr_radius_client_bio_activate;
bio_cb.write_blocked = fr_radius_client_bio_write_blocked;
bio_cb.write_resume = fr_radius_client_bio_write_resume;
fr_bio_packet_t *fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg) CC_HINT(nonnull);
-int fr_radius_client_bio_connect(fr_bio_packet_t *bio) CC_HINT(nonnull);
-
int fr_radius_client_fd_bio_cancel(fr_bio_packet_t *bio, fr_packet_t *packet) CC_HINT(nonnull);
fr_radius_client_bio_info_t const *fr_radius_client_bio_info(fr_bio_packet_t *bio) CC_HINT(nonnull);
int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id);
void fr_radius_client_bio_cb_set(fr_bio_packet_t *bio, fr_bio_packet_cb_funcs_t const *cb);
+
+void fr_radius_client_bio_connect(fr_event_list_t *el, int fd, int flags, void *uctx);