diff options
Diffstat (limited to 'src/buffio.c')
-rw-r--r-- | src/buffio.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/buffio.c b/src/buffio.c new file mode 100644 index 0000000..1e13b4d --- /dev/null +++ b/src/buffio.c @@ -0,0 +1,202 @@ +#include "buffio.h" + +#define BUFSIZE 10240 + +static void buffio_set_callbacks(struct buffio *b); +static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user); +static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user); + +struct buffio buffio_new(int fd) { + struct buffio *b; + assert(b >= 0); + + b = malloc(sizeof(struct buffio)); + assert(b); + memset(b, 0, sizeof(struct buffio)); + + b->fd = fd; + b->input_buf = malloc(BUFSIZE); + assert(b->input_buf); + b->input_buf_len = 0; + + b->output_buf = malloc(BUFSIZE); + assert(b->output_buf); + b->output_buf_len = 0; + + buffio_set_callbacks(b); + + return b; +} + +static void buffio_close_fd(struct buffio *b) { + assert(b); + + if (b->b_read_cb) + event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + + if (b->b_write_cb) + event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + + if (b->fd >= 0) + close(b->fd); + + b->b_read_cb = b->b_write_cb = 0; + b->fd = -1; +} + + +void buffio_free(struct buffio *b) { + buffio_close_fd(b); + free(b->output_buf); + free(b->input_buf); + free(b); +} + +static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user) { + struct buffio *b = user; + assert(source && b && b->fd == fd && event == OOP_READ); + + if (b->input_length < BUFSIZE) { + ssize_t s; + size_t m, l; + + i = (b->input_index + b->input_length) % BUFSIZE; + + m = BUFSIZE-b->input_length; + if (m > BUFSIZE-i) + m = BUFSIZE-i; + + if ((s = read(fd, b->input_buf+i, m)) < 0) { + daemon_log(LOG_ERR, "Failed to read from file descriptor: %s", strerror(errno)); + return OOP_HALT; + } + + if (!s) { + buffio_close_fd(b); + if (b->eof_cb) + b->eof_cb(b, b->user); + return OOP_CONTINUE; + } + + assert(s <= m); + b->input_length += s; + } + + buffio_set_callbacks(b); + return OOP_CONTINUE; +} + +static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user) { + struct buffio *b = user; + assert(source && b && b->fd == fd && event == OOP_WRITE); + + if (b->output_buf > 0) { + ssize_t s; + size_t m; + + m = b->output_length; + if (m > BUFSIZE-b->output_index) + m = BUFSIZE-b->output_index; + + if ((s = write(fd, b->output_buf+b->output_index, m)) < 0) { + daemon_log(LOG_ERR, "Failed to write to file descriptor: %s", strerror(errno)); + return OOP_HALT; + } + + if (!s) { + buffio_close_fd(b); + if (b->eof_cb) + b->eof_cb(b, b->user); + return OOP_CONTINUE; + } + + assert(s <= m); + b->output_index = (b->output_index + s) % BUFSIZE; + b->ouput_length -= s; + } + + buffio_set_callbacks(b); + return OOP_CONTINUE; + +} + +static void buffio_set_callbacks(struct buffio *b) { + assert(b && b->fd >= 0 && event_source); + + if (b->input_length < BUFSIZE) { + if (!b->b_read_cb) { /* Enable the callback */ + event_source->on_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + b->b_read_cb = 1; + } + } else { + if (b->read_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + b->read_cb = 0; + } + } + + if (b->output_length > 0) { + if (!b->b_write_cb) { /* Enable the callback */ + event_source->on_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + b->b_write_cb = 1; + } + } else { + if (b->b_write_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + b->b_write_cb = 0; + } + } + +} + +int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { + assert(b && s && l); + + if (l < BUFFSIZE - b->output_length) { + daemon_log(LOG_ERR, "buffio_write() with too much data called"); + return -1; + } + + + while (l >= 0) { + i = (b->ouput_index + b->ouput_length) % BUFSIZE; + + m = BUFSIZE-b->output_length; + if (m > BUFSIZE-i) + m = BUFSIZE-i; + + memcpy(b->output_buf+i, d, m); + + l -= m; + b->output_length += m; + } + + buffio_set_callbacks(b); + + return 0; +} + +int buffio_print(struct buffio *b, const char *s) { + assert(b && s); + return buffio_write(b, (uint8_t*) s, strlen(s)); +} + +int buffio_command(struct buffio *b, const char *c) { + assert(b && c); + + buffio_flush_input(b); + return buffio_print(b, c); +} + +void buffio_flush_input(struct buffio *b) { + assert(b); + + b->input_length = b->input_index = 0; + buffio_set_callbacks(b); +} + +int buffio_find_input(struct buffio *b, const char *c) { + assert(b && c); + + +} |