summaryrefslogtreecommitdiffstats
path: root/src/buffio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffio.c')
-rw-r--r--src/buffio.c202
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);
+
+
+}