#include #include #include #include "al.h" #include "sio.h" #include typedef struct { BIO *bio; size_t inputsize; al_label_t data_label; al_label_t eof_label; al_label_t error_label; char eof; char error; size_t total; } private_t; /* * create stage * * allocate private instance data */ static sio_rc_t siobio_init(sio_t *sio, void **u) { private_t *my; my = (private_t *)malloc(sizeof(private_t)); if (my == NULL) return SIO_ERR_MEM; my->bio = NULL; my->eof = '\0'; my->error = '\0'; sio_label(sio, SIO_LN_DATA, &my->data_label); sio_label(sio, SIO_LN_EOF, &my->eof_label); sio_label(sio, SIO_LN_ERROR, &my->error_label); *u = my; return SIO_OK; } /* * configure stage * * pass two void pointers */ static sio_rc_t siobio_configure(sio_t *sio, void *u, void *obj, void *val) { private_t *my = (private_t *)u; const char *name = (const char *)obj; if (!strcmp(name, "bio")) { my->bio = (BIO *)val; } else if (!strcmp(name, "inputsize")) { my->inputsize = *(int *)val; } else { return SIO_ERR_ARG; } return SIO_OK; } /* * destroy stage */ static sio_rc_t siobio_cleanup(sio_t *sio, void *u) { private_t *my = (private_t *)u; free(my); return SIO_OK; } static sio_rc_t siobio_openr(sio_t *sio, al_t *al, void *u) { return SIO_OK; } static sio_rc_t siobio_closer(sio_t *sio, al_t *al, void *u) { return SIO_OK; } static sio_rc_t siobio_openw(sio_t *sio, al_t *al, void *u) { return SIO_OK; } static sio_rc_t siobio_closew(sio_t *sio, al_t *al, void *u) { return SIO_OK; } static void freebiobuf(char *p, size_t n, void *u) { free(p); } static sio_rc_t siobio_input(sio_t *sio, al_t *al, void *u) { private_t *my = (private_t *)u; char *p; int n; n = BIO_pending(my->bio); if (n == 0 || n > my->inputsize) n = my->inputsize; p = malloc(n); if (p != NULL) do { n = BIO_read(my->bio, p, n); } while (n <= 0 && BIO_should_retry(my->bio)); if (p == NULL || n <= 0) { free(p); if (n < -1) al_append_bytes(al, &my->error, sizeof(my->error), my->error_label); else al_append_bytes(al, &my->eof, sizeof(my->eof), my->eof_label); } else al_attach_buffer(al, p, n, my->data_label, freebiobuf, NULL); return SIO_SCHED_DOWN; } static al_rc_t siobio_write_chunk(al_chunk_t *alc, void *u) { private_t *my = (private_t *)u; al_rc_t arc = AL_OK; if (al_same_label(alc, my->data_label)) { char *p = al_chunk_ptr(alc, 0); int n = al_chunk_len(alc); int i, t; for (t=0; tbio, p+t, n-t); if (i <= 0) { if (!BIO_should_retry(my->bio)) { arc = AL_ERR_EOF; break; } i = 0; } my->total += i; } } else { my->total += al_chunk_len(alc); } return arc; } static sio_rc_t siobio_output(sio_t *sio, al_t *al, void *u) { private_t *my = (private_t *)u; my->total = 0; al_traverse_cb(al, 0, al_bytes(al), AL_FORWARD, my->data_label, siobio_write_chunk, (void *)my); al_splice(al, 0, al_bytes(al), NULL, NULL); return SIO_SCHED_DOWN; } sio_module_t sio_module_bio = { "bio", siobio_init, siobio_configure, siobio_cleanup, siobio_openr, siobio_closer, siobio_openw, siobio_closew, siobio_input, siobio_output };