From: Alan T. DeKok Date: Thu, 7 Aug 2025 14:59:17 +0000 (-0400) Subject: on TCP EOF, flush all writes, and shut down the BIOs X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2e4ffeb7c96cead1a9a86b452e53e8d95a983db;p=thirdparty%2Ffreeradius-server.git on TCP EOF, flush all writes, and shut down the BIOs --- diff --git a/src/lib/bio/base.c b/src/lib/bio/base.c index 0e00171cec9..f1dbf637846 100644 --- a/src/lib/bio/base.c +++ b/src/lib/bio/base.c @@ -98,27 +98,24 @@ ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNU int fr_bio_shutdown(fr_bio_t *bio) { int rcode; - fr_bio_t *this, *first; + fr_bio_t *head, *this; fr_bio_common_t *my; /* * Find the first bio in the chain. */ - for (this = bio; fr_bio_prev(this) != NULL; this = fr_bio_prev(this)) { - /* nothing */ - } - first = this; + head = fr_bio_head(bio); /* * We're in the process of shutting down, don't call ourselves recursively. */ - my = (fr_bio_common_t *) this; + my = (fr_bio_common_t *) head; if (my->bio.read == fr_bio_shutdown_read) return 0; /* * Walk back down the chain, calling the shutdown functions. */ - for (/* nothing */; this != NULL; this = fr_bio_next(this)) { + for (this = head; this != NULL; this = fr_bio_next(this)) { my = (fr_bio_common_t *) this; if (my->priv_cb.shutdown) { @@ -136,10 +133,10 @@ int fr_bio_shutdown(fr_bio_t *bio) * Call the application shutdown routine to tell it that * the BIO has been successfully shut down. */ - my = (fr_bio_common_t *) first; + my = (fr_bio_common_t *) head; if (my->cb.shutdown) { - rcode = my->cb.shutdown(first); + rcode = my->cb.shutdown(head); if (rcode < 0) return rcode; my->cb.shutdown = NULL; } diff --git a/src/lib/bio/base.h b/src/lib/bio/base.h index cf2b65b4f67..c5a3134ea59 100644 --- a/src/lib/bio/base.h +++ b/src/lib/bio/base.h @@ -137,6 +137,17 @@ static inline CC_HINT(nonnull) fr_bio_t *fr_bio_next(fr_bio_t *bio) return fr_dlist_entry_to_item(offsetof(fr_bio_t, entry), next); } +static inline CC_HINT(nonnull) fr_bio_t *fr_bio_head(fr_bio_t *bio) +{ + fr_bio_t *this, *prev; + + for (this = bio; (prev = fr_bio_prev(this)) != NULL; this = prev) { + /* nothing */ + } + + return this; +} + /** Read raw data from a bio * * @param bio the binary IO handler diff --git a/src/lib/bio/fd.c b/src/lib/bio/fd.c index 44262a905f9..5dabcca8387 100644 --- a/src/lib/bio/fd.c +++ b/src/lib/bio/fd.c @@ -144,6 +144,18 @@ static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, voi retry: rcode = read(my->info.socket.fd, buffer, size); if (rcode == 0) { + fr_bio_t *head; + + /* + * Flush any pending writes, shut down the BIO, and then mark it as EOF. + */ + head = fr_bio_head(bio); + + (void) fr_bio_write(head, NULL, NULL, SIZE_MAX); + + rcode = fr_bio_shutdown(head); + if (rcode < 0) return rcode; + fr_bio_eof(bio); return 0; }