From: Alan T. DeKok Date: Thu, 6 Jun 2024 13:43:58 +0000 (-0400) Subject: more gluing in of EOF callbacks X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3fdbcaeb8722c8b25dd9f3a58f73b3d8e7a3be25;p=thirdparty%2Ffreeradius-server.git more gluing in of EOF callbacks --- diff --git a/src/bin/radclient-ng.c b/src/bin/radclient-ng.c index e6dede01531..7da8f4c08e8 100644 --- a/src/bin/radclient-ng.c +++ b/src/bin/radclient-ng.c @@ -1099,9 +1099,18 @@ static int client_bio_write_resume(fr_bio_packet_t *bio) static NEVER_RETURNS void client_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, - int fd_errno, UNUSED void *uctx) + int fd_errno, void *uctx) { + fr_bio_packet_t *client = uctx; + ERROR("Failed in connection - %s", fr_syserror(fd_errno)); + + /* + * Cleanly close the BIO, so that we exercise the shutdown path. + */ + fr_assert(client == client_bio); + TALLOC_FREE(client_bio); + fr_exit_now(1); } diff --git a/src/lib/bio/base.h b/src/lib/bio/base.h index 56aa564ffa2..0f00397e956 100644 --- a/src/lib/bio/base.h +++ b/src/lib/bio/base.h @@ -85,6 +85,7 @@ typedef void (*fr_bio_callback_t)(fr_bio_t *bio); /* activate / shutdown callbac typedef struct { fr_bio_callback_t activate; //!< called when the BIO is ready to be used + fr_bio_callback_t eof; //!< called when the BIO is at EOF fr_bio_callback_t shutdown; //!< called when the BIO is being shut down fr_bio_io_t read_blocked; diff --git a/src/lib/bio/fd.c b/src/lib/bio/fd.c index 4c142019c49..7557e88ef96 100644 --- a/src/lib/bio/fd.c +++ b/src/lib/bio/fd.c @@ -100,6 +100,8 @@ static int fr_bio_fd_destructor(fr_bio_fd_t *my) fr_assert(!fr_bio_prev(&my->bio)); fr_assert(!fr_bio_next(&my->bio)); + if (!my->info.eof && my->cb.eof) my->cb.eof(&my->bio); + if (my->cb.shutdown) my->cb.shutdown(&my->bio); return fr_bio_fd_close(&my->bio); @@ -130,6 +132,7 @@ retry: rcode = read(my->info.socket.fd, buffer, size); if (rcode == 0) { fr_bio_eof(bio); + if (my->cb.eof) my->cb.eof(&my->bio); /* inform the application that we're at EOF */ return 0; } diff --git a/src/lib/bio/fd_errno.h b/src/lib/bio/fd_errno.h index a3341624352..7f58e0eb499 100644 --- a/src/lib/bio/fd_errno.h +++ b/src/lib/bio/fd_errno.h @@ -27,6 +27,26 @@ case EAGAIN: } return fr_bio_error(IO_WOULD_BLOCK); +#ifndef NDEBUG +case ENOTCONN: + /* + * We're doing a read/write to a socket which isn't connected. This is a failure of the + * application state machine. + */ + fr_assert(0); + break; +#endif + +case ECONNRESET: +case EPIPE: + /* + * The other end closed the connection, signal the application that it's a (maybe) clean close, + * and set EOF on the BIO. + */ + fr_bio_eof(&my->bio); + if (my->cb.eof) my->cb.eof(&my->bio); /* inform the application that we're at EOF */ + return 0; + default: /* * Some other error, it's fatal. diff --git a/src/protocols/radius/client.c b/src/protocols/radius/client.c index 88d6d26a363..0c90587617c 100644 --- a/src/protocols/radius/client.c +++ b/src/protocols/radius/client.c @@ -623,6 +623,13 @@ int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id) return fr_radius_code_id_force(my->codes, code, id); } +static void fr_radius_client_bio_eof(fr_bio_t *bio) +{ + fr_radius_client_fd_bio_t *my = bio->uctx; + + if (my->common.cb.eof) my->common.cb.eof(&my->common); +} + /** Callback for when the FD is activated, i.e. connected. * */ @@ -633,8 +640,6 @@ static void fr_radius_client_bio_activate(fr_bio_t *bio) fr_assert(!my->info.connected); my->info.connected = true; - - fr_assert(0); } void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx) @@ -782,7 +787,12 @@ void fr_radius_client_bio_cb_set(fr_bio_packet_t *bio, fr_bio_packet_cb_funcs_t my->common.cb = *cb; - fr_bio_cb_set(my->fd, &bio_cb); fr_bio_cb_set(my->mem, &bio_cb); fr_bio_cb_set(my->retry, &bio_cb); + + /* + * Only the FD bio gets an EOF callback. + */ + bio_cb.eof = fr_radius_client_bio_eof; + fr_bio_cb_set(my->fd, &bio_cb); }