summaryrefslogtreecommitdiffstats
path: root/src/buffio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffio.c')
-rw-r--r--src/buffio.c231
1 files changed, 162 insertions, 69 deletions
diff --git a/src/buffio.c b/src/buffio.c
index 2c3a7fb..25ba5a4 100644
--- a/src/buffio.c
+++ b/src/buffio.c
@@ -1,12 +1,25 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <oop.h>
+
+#include <libdaemon/dlog.h>
+
#include "buffio.h"
+#include "main.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) {
+static void buffio_set_input_callbacks(struct buffio *b);
+static void buffio_set_output_callbacks(struct buffio *b);
+
+struct buffio* buffio_new(int ifd, int ofd) {
struct buffio *b;
assert(b >= 0);
@@ -14,19 +27,21 @@ struct buffio buffio_new(int fd) {
assert(b);
memset(b, 0, sizeof(struct buffio));
- b->fd = fd;
+ b->ifd = ifd;
+ b->ofd = ofd;
b->input_buf = malloc(b->input_max_length = BUFSIZE);
assert(b->input_buf);
- b->input_buf_len = b->input_index = 0;
- b->input_watermark = 2; /* Read some more data if 2 or less bytes are in the input buffer */
+ b->input_length = b->input_index = 0;
+ b->input_watermark = b->input_max_length; /* Read some more data if possible */
b->output_buf = malloc(b->output_max_length = BUFSIZE);
assert(b->output_buf);
b->output_length = b->output_index = 0;
b->output_watermark = 1; /* Write some data if 1 or more bytes are in the output buffer */
- buffio_set_callbacks(b);
+ buffio_set_input_callbacks(b);
+ buffio_set_output_callbacks(b);
return b;
}
@@ -35,16 +50,18 @@ 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);
+ event_source->cancel_fd(event_source, b->ifd, OOP_READ);
if (b->b_write_cb)
- event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b);
+ event_source->cancel_fd(event_source, b->ofd, OOP_WRITE);
- if (b->fd >= 0)
- close(b->fd);
+ if (b->ifd >= 0)
+ close(b->ifd);
+ if (b->ofd >= 0 && b->ofd != b->ifd)
+ close(b->ofd);
b->b_read_cb = b->b_write_cb = 0;
- b->fd = -1;
+ b->ifd = b->ofd = -1;
}
@@ -55,13 +72,69 @@ void buffio_free(struct buffio *b) {
free(b);
}
+#ifdef IODEBUG
+static void esc_print(const char*c, const uint8_t *b, size_t l) {
+ size_t i;
+ fprintf(stderr, "%s", c);
+ for (i = 0; i < l; i++, b++)
+ fputc(*b < 32 ? '.' : *b, stderr);
+
+ fprintf(stderr, "\n");
+};
+#endif
+
+static void buffio_normalize(struct buffio *b) {
+ assert(b);
+
+ assert(b->input_index < b->input_max_length);
+ assert(b->input_length <= b->input_max_length);
+
+ if (!b->input_length) /* This will optimize throughput a bit */
+ b->input_index = 0;
+
+ if (!b->output_length) /* This will optimize throughput a bit */
+ b->output_index = 0;
+}
+
+static void buffio_set_input_callbacks(struct buffio *b) {
+ assert(b && b->ifd >= 0 && event_source);
+
+ if (b->input_length <= b->input_watermark) {
+ if (!b->b_read_cb) { /* Enable the callback */
+ event_source->on_fd(event_source, b->ifd, OOP_READ, buffio_read_cb, b);
+ b->b_read_cb = 1;
+ }
+ } else {
+ if (b->b_read_cb) { /* Disable the callback */
+ event_source->cancel_fd(event_source, b->ifd, OOP_READ);
+ b->b_read_cb = 0;
+ }
+ }
+}
+
+static void buffio_set_output_callbacks(struct buffio *b) {
+ assert(b && b->ofd >= 0 && event_source);
+
+ if (b->output_length >= b->output_watermark) {
+ if (!b->b_write_cb) { /* Enable the callback */
+ event_source->on_fd(event_source, b->ofd, 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->ofd, OOP_WRITE);
+ b->b_write_cb = 0;
+ }
+ }
+}
+
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);
+ assert(source && b && b->ifd == fd && event == OOP_READ);
if (b->input_length < b->input_max_length) {
ssize_t s;
- size_t m, l;
+ size_t m, i;
i = (b->input_index + b->input_length) % b->input_max_length;
@@ -74,6 +147,10 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u
return OOP_HALT;
}
+#ifdef IODEBUG
+ esc_print("INPUT: ", b->input_buf+i, s);
+#endif
+
if (!s) {
buffio_close_fd(b);
if (b->eof_cb)
@@ -96,9 +173,9 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u
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);
+ assert(source && b && b->ofd == fd && event == OOP_WRITE);
- if (b->output_buf > 0) {
+ if (b->output_length > 0) {
ssize_t s;
size_t m;
@@ -111,6 +188,10 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *
return OOP_HALT;
}
+#ifdef IODEBUG
+ esc_print("OUTPUT: ", b->output_buf+b->output_index, s);
+#endif
+
if (!s) {
buffio_close_fd(b);
if (b->eof_cb)
@@ -120,7 +201,7 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *
assert(s <= m);
b->output_index = (b->output_index + s) % b->output_max_length;
- b->ouput_length -= s;
+ b->output_length -= s;
}
buffio_normalize(b);
@@ -133,51 +214,24 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *
}
-static void buffio_set_input_callbacks(struct buffio *b) {
- assert(b && b->fd >= 0 && event_source);
-
- if (b->input_length <= b->input_watermark) {
- 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;
- }
- }
-}
-
-static void buffio_set_output_callbacks(struct buffio *b) {
- assert(b && b->fd >= 0 && event_source);
-
- if (b->output_length >= b->output_watermark) {
- 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);
+ assert(b && d && l);
- if (l < b->output_max_length - b->output_length) {
+ if (l > b->output_max_length - b->output_length) {
daemon_log(LOG_ERR, "buffio_write() with too much data called");
return -1;
}
+ while (l > 0) {
+ size_t m, i;
+
+ i = (b->output_index + b->output_length) % b->output_max_length;
- while (l >= 0) {
- i = (b->ouput_index + b->ouput_length) % b->ouput_max_length;
+ m = l;
+ if (m > b->output_max_length-b->output_length)
+ m = b->output_max_length-b->output_length;
- m = b->ouput_max_length-b->output_length;
if (m > b->output_max_length-i)
m = b->output_max_length-i;
@@ -188,7 +242,7 @@ int buffio_write(struct buffio *b, const uint8_t *d, size_t l) {
}
buffio_set_output_callbacks(b);
- buffio_normalize();
+ buffio_normalize(b);
return 0;
}
@@ -200,7 +254,7 @@ int buffio_print(struct buffio *b, const char *s) {
int buffio_command(struct buffio *b, const char *c) {
assert(b && c);
-
+
buffio_flush_input(b);
return buffio_print(b, c);
}
@@ -209,29 +263,19 @@ void buffio_flush_input(struct buffio *b) {
assert(b);
b->input_length = b->input_index = 0;
- buffio_set_callbacks(b);
+ buffio_set_input_callbacks(b);
}
-static void buffio_normalize(struct buffio *b) {
- assert(b);
-
- assert(b->input_index < b->input_max_length);
- assert(b->input_length <= b->input_max_length);
-
- if (!b->input_length) /* This will optimize throughput a bit */
- b->input_index = 0;
-}
-
int buffio_find_input(struct buffio *b, const char *c) {
- size_t l, cl, j;
+ size_t l, cl, i;
assert(b && c && *c);
-
+
cl = strlen(c);
for (i = b->input_index, l = b->input_length; l >= cl; i = (i+1) % b->input_max_length, l--) {
- char *p;
- size_t i;
+ const char *p;
+ size_t j;
for (j = i, p = c; *p && *p == b->input_buf[j]; p++, j = (j+1) % b->input_max_length);
@@ -240,6 +284,7 @@ int buffio_find_input(struct buffio *b, const char *c) {
b->input_length = l-cl;
buffio_normalize(b);
+ buffio_set_input_callbacks(b);
return 1;
}
}
@@ -248,3 +293,51 @@ int buffio_find_input(struct buffio *b, const char *c) {
}
+char *buffio_read_line(struct buffio *b, char *c, size_t l) {
+ size_t i;
+ assert(b && c && l);
+
+ /* Look for a \n */
+ for (i = 0; i < b->input_length && i < l-1; i++) {
+ if (b->input_buf[(b->input_index+i) % b->input_max_length] == '\n') {
+ size_t j;
+
+ /* Once again, now copy */
+ for (j = 0;; j++) {
+ c[j] = b->input_buf[(b->input_index+j) % b->input_max_length];
+
+ /* Finished? */
+ if (c[j] == '\n') {
+ c[j+1] = 0;
+
+ b->input_index = (b->input_index+j+1) % b->input_max_length;
+ b->input_length -= j+1;
+ buffio_set_input_callbacks(b);
+ buffio_normalize(b);
+ return c;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void buffio_dump(struct buffio *b) {
+ assert(b);
+ size_t i;
+
+ fprintf(stderr, "%p INPUT_BUFFER: [", b);
+ for (i = 0; i < b->input_length; i++) {
+ char c = b->input_buf[(i + b->input_index) % b->input_max_length];
+ fputc(c < 32 ? '.' : c, stderr);
+ }
+ fprintf(stderr, "]\n");
+
+ fprintf(stderr, "%p OUTPUT_BUFFER: [", b);
+ for (i = 0; i < b->output_length; i++) {
+ char c = b->output_buf[(i + b->output_index) % b->output_max_length];
+ fputc(c < 32 ? '.' : c, stderr);
+ }
+ fprintf(stderr, "]\n");
+}