]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
just use our own buffer for the pipes
authorAlan T. DeKok <aland@freeradius.org>
Sun, 1 Mar 2026 19:31:52 +0000 (14:31 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 1 Mar 2026 20:33:36 +0000 (15:33 -0500)
and tweak read/write logic to be better.

src/lib/bio/pipe.c

index c8b4a38c4196d131c15df7dbd1e059f8046b1757..a0739914ce3c1a5faefc429f886edf6f69e88b86 100644 (file)
@@ -23,7 +23,7 @@
  */
 #include <freeradius-devel/bio/bio_priv.h>
 #include <freeradius-devel/bio/null.h>
-#include <freeradius-devel/bio/mem.h>
+#include <freeradius-devel/bio/buf.h>
 
 #include <freeradius-devel/bio/pipe.h>
 
@@ -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;