aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou/sendbuf.c
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2012-12-01 04:22:41 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2012-12-01 04:22:41 +0100
commit94d722d144b92cf64f7be022f542e0cef3341780 (patch)
tree82e3d3aed66ac8a25b3d23aa631569d7bc1939c4 /libglouglou/sendbuf.c
parentexplictly set source and headers (diff)
downloadglouglou-94d722d144b92cf64f7be022f542e0cef3341780.tar.xz
glouglou-94d722d144b92cf64f7be022f542e0cef3341780.zip
work in progress on implementing a send buffer
Diffstat (limited to 'libglouglou/sendbuf.c')
-rw-r--r--libglouglou/sendbuf.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/libglouglou/sendbuf.c b/libglouglou/sendbuf.c
new file mode 100644
index 0000000..078d6a6
--- /dev/null
+++ b/libglouglou/sendbuf.c
@@ -0,0 +1,117 @@
+#include "sendbuf.h"
+
+/*
+ * Public
+ */
+
+/*
+ * Create a sendbuf
+ * send_func should return the number of successfuly sent bytes
+ */
+struct sendbuf *
+sendbuf_init(struct event_base *ev_base, int size, int sndbuf_max, int msec_max,
+ int (*send_func)(void *, int, void *), void *usrdata)
+{
+ struct sendbuf *sbuf = NULL;
+ struct event ev_timer;
+ struct timeval *tv;
+ void *buffer;
+ void *data;
+
+ sbuf = calloc(1, sizeof(struct sendbuf));
+ if (!sbuf)
+ return NULL;
+ sbuf->ev_base = ev_base;
+ sbuf->sndbuf_max = sndbuf_max;
+ sbuf->msec_max = msec_max;
+ sbuf->usrdata = usrdata;
+ sbuf->send_func = send_func;
+ sbuf->buffer_size = size;
+ sbuf->buffer = malloc(sbuf->buffer_size);
+ if (!sbuf->buffer)
+ goto err;
+
+ ev_timer = evtimer_new(ev_base, cb_timer, sbuf);
+ sbuf->ev_timer = ev_timer;
+ sbuf->ev_timer_tv.tv_usec = msec_max * 1000;
+ evtimer_add(ev, &sbuf->ev_timer_tv);
+
+ return sbuf;
+
+err:
+ sendbuf_shutdown(sbuf);
+ return NULL;
+}
+
+void
+sendbuf_shutdown(struct sendbuf *sbuf)
+{
+ if (sbuf->send_timer)
+ event_del(sbuf->send_timer);
+ if (sbuf->buffer && sbuf->send_func)
+ flushbuf(sbuf);
+ if (sbuf->buffer)
+ free(sbuf->buffer);
+ free(sbuf);
+}
+
+/*
+ * Returns a buffer to write data to be sent
+ * might return NULL if the sendbuf is temporary full
+ */
+void *
+sendbuf_getoken(struct sendbuf *sbuf, int size)
+{
+ if (sbuf->buffer_pos + size >= sbuf->buffer_size)
+ if (flushbuf(sbuf) == -1)
+ return NULL;
+
+ return sbuf->buffer_pos;
+}
+
+/*
+ * Private
+ */
+
+/*
+ * Note that you can still add data to the buffer even if flushing is in
+ * progress
+ */
+int
+flushbuf(struct sendbuf *sbuf)
+{
+ int sent;
+ int sent_total;
+ int len;
+
+ sbuf->flushing = 1;
+
+ do {
+ pos = sbuf->buffer + sbuf->flushed_len;
+ if (sbuf->buffer_pos > sbuf->sndbuf_max)
+ tosend = sbuf->sndbuf_max;
+ else
+ tosend = sbuf->buffer_pos;
+ sent = sbuf->send_func(sbuf->buffer + pos, tosend, sbuf->usrdata);
+ sbuf->flushed_len = sbuf->flushed_len + sent;
+ if (sent == -1) {
+ // XXX handle erorr
+ } else if (sent < tosend) {
+ return -1;
+ }
+ } while (sbuf->flushed_len < sbuf->buffer_pos)
+
+ sbuf->flushing = 0;
+ sbuf->flushed_len = 0;
+ return 0;
+}
+
+void
+cb_timer(evutil_socket_t fd, short what, void *arg)
+{
+ struct sendbuf *sbuf;
+
+ sbuf = arg;
+ flushbuf(sbuf);
+ evtimer_add(sbuf->ev_timer, &sbuf->ev_timer_tv);
+}