#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); }