From: Alan T. DeKok Date: Sun, 1 Mar 2026 19:31:52 +0000 (-0500) Subject: just use our own buffer for the pipes X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bb9f93e58de416aea824a1ae4b650b47ae45fc9d;p=thirdparty%2Ffreeradius-server.git just use our own buffer for the pipes and tweak read/write logic to be better. --- diff --git a/src/lib/bio/pipe.c b/src/lib/bio/pipe.c index c8b4a38c419..a0739914ce3 100644 --- a/src/lib/bio/pipe.c +++ b/src/lib/bio/pipe.c @@ -23,7 +23,7 @@ */ #include #include -#include +#include #include @@ -35,7 +35,7 @@ typedef struct { FR_BIO_COMMON; - fr_bio_t *next; + fr_bio_buf_t buf; //!< for reading and writing bool eof; //!< are we at EOF? @@ -58,38 +58,19 @@ static int fr_bio_pipe_destructor(fr_bio_pipe_t *my) * * Once EOF is set, any pending data is read, and then EOF is returned. */ -static ssize_t fr_bio_pipe_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size) +static ssize_t fr_bio_pipe_read(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size) { - ssize_t rcode; fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t); - fr_assert(my->next != NULL); - pthread_mutex_lock(&my->mutex); - rcode = my->next->read(my->next, packet_ctx, buffer, size); - if ((rcode == 0) && my->eof) { - my->priv_cb.eof = NULL; - pthread_mutex_unlock(&my->mutex); - - /* - * Don't call our EOF function. But do tell the other BIOs that we're at EOF. - */ - fr_bio_eof(bio); - return 0; + size = fr_bio_buf_read(&my->buf, buffer, size); - } + if ((size == 0) && my->eof) my->bio.read = fr_bio_null_read; pthread_mutex_unlock(&my->mutex); - /* - * There is room to write more data. - * - * @todo - only signal when we transition from BLOCKED to unblocked. - */ - if (rcode > 0) { - my->signal.writeable(&my->bio); - } + if (size > 0) my->signal.writeable(&my->bio); - return rcode; + return size; } @@ -97,32 +78,24 @@ static ssize_t fr_bio_pipe_read(fr_bio_t *bio, void *packet_ctx, void *buffer, s * * Once EOF is set, no further writes are possible. */ -static ssize_t fr_bio_pipe_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size) +static ssize_t fr_bio_pipe_write(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size) { - ssize_t rcode; + size_t room; fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t); - fr_assert(my->next != NULL); - pthread_mutex_lock(&my->mutex); - if (!my->eof) { - rcode = my->next->write(my->next, packet_ctx, buffer, size); - - /* - * There is more data to read. - * - * @todo - only signal when we transition from no data to data. - */ - if (rcode > 0) { - my->signal.readable(&my->bio); - } - + room = fr_bio_buf_write_room(&my->buf); + if (room > 0) { + if (room < size) size = room; + (void) fr_bio_buf_write(&my->buf, buffer, size); /* always succeeds */ } else { - rcode = fr_bio_error(IO_WOULD_BLOCK); + size = 0; } pthread_mutex_unlock(&my->mutex); - return rcode; + if (size > 0) my->signal.readable(&my->bio); + + return size; } /** Shutdown callback. @@ -130,16 +103,14 @@ static ssize_t fr_bio_pipe_write(fr_bio_t *bio, void *packet_ctx, void const *bu */ static int fr_bio_pipe_shutdown(fr_bio_t *bio) { - int rcode; fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t); - fr_assert(my->next != NULL); - pthread_mutex_lock(&my->mutex); - rcode = fr_bio_shutdown(my->next); + my->bio.read = fr_bio_fail_read; + my->bio.write = fr_bio_fail_write; pthread_mutex_unlock(&my->mutex); - return rcode; + return 0; } /** Set EOF. @@ -152,7 +123,9 @@ static int fr_bio_pipe_eof(fr_bio_t *bio) fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t); pthread_mutex_lock(&my->mutex); - my->eof = true; + my->eof = true; + my->bio.write = fr_bio_null_write; + if (fr_bio_buf_used(&my->buf) == 0) my->bio.read = fr_bio_null_read; pthread_mutex_unlock(&my->mutex); /* @@ -168,7 +141,7 @@ static int fr_bio_pipe_eof(fr_bio_t *bio) * need to be called twice. That way a free in each context won't result in a race condition on two mutex * locks. * - * For now, iqt's too difficult to emulate the pipe[2] behavior, where two identical "connected" things are + * For now, it's too difficult to emulate the pipe[2] behavior, where two identical "connected" things are * returned, and either can be used for reading or for writing. * * i.e. a pipe is really a mutex-protected memory buffer. One side should call write (and never read). The @@ -178,7 +151,8 @@ static int fr_bio_pipe_eof(fr_bio_t *bio) */ fr_bio_t *fr_bio_pipe_alloc(TALLOC_CTX *ctx, fr_bio_pipe_cb_funcs_t *cb, size_t buffer_size) { - fr_bio_pipe_t *my; + fr_bio_pipe_t *my; + uint8_t *buffer; if (!cb->readable || !cb->writeable) return NULL; @@ -188,14 +162,16 @@ fr_bio_t *fr_bio_pipe_alloc(TALLOC_CTX *ctx, fr_bio_pipe_cb_funcs_t *cb, size_t my = talloc_zero(ctx, fr_bio_pipe_t); if (!my) return NULL; - my->next = fr_bio_mem_sink_alloc(my, buffer_size); - if (!my->next) { + buffer = talloc_array(my, uint8_t, buffer_size); + if (!buffer) { talloc_free(my); return NULL; } my->signal = *cb; + fr_bio_buf_init(&my->buf, buffer, buffer_size); + pthread_mutex_init(&my->mutex, NULL); my->bio.read = fr_bio_pipe_read;