*/
#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>
typedef struct {
FR_BIO_COMMON;
- fr_bio_t *next;
+ fr_bio_buf_t buf; //!< for reading and writing
bool eof; //!< are we at EOF?
*
* 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;
}
*
* 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.
*/
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.
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);
/*
* 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
*/
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;
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;