replace old sock_test with new transport_test new-transport
authorTero Marttila <terom@fixme.fi>
Sun, 03 May 2009 17:19:05 +0300
branchnew-transport
changeset 166 cb8cb023cf06
parent 165 b3e95108c884
child 167 0d2d8ca879d8
replace old sock_test with new transport_test
src/sock_test.c
src/sock_test.h
src/transport_test.c
src/transport_test.h
--- a/src/sock_test.c	Sun May 03 17:18:16 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,288 +0,0 @@
-#include "sock_test.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-/**
- * Grow buf->vecs as needed, to ensure that buf->write_vec is valid
- */
-static err_t sock_test_grow_buf (struct io_buf *buf)
-{
-    size_t read_vec_offset = buf->read_vec ? (buf->read_vec - buf->vecs) : 0;
-    size_t write_vec_offset = buf->write_vec ? (buf->write_vec - buf->vecs) : 0;
-    struct io_vec *v;
-    struct io_vec *vecs_tmp = buf->vecs;
-
-    // don't grow if not full
-    if (buf->vecs && buf->write_vec < buf->vecs + buf->count)
-        return SUCCESS;
-
-    // new size
-    buf->count = buf->count * 2 + 1;
-
-    // grow
-    if ((buf->vecs = realloc(buf->vecs, buf->count * sizeof(struct io_vec))) == NULL) {
-        // restore old value
-        buf->vecs = vecs_tmp;
-
-        return ERR_CALLOC;
-    }
-
-    // set vec
-    buf->write_vec = buf->vecs + write_vec_offset;
-    buf->read_vec = buf->vecs + read_vec_offset;
-
-    // zero new vecs
-    for (v = buf->write_vec; v < buf->vecs + buf->count; v++) {
-        v->buf = NULL;
-        v->len = 0;
-    }
-
-    // ok
-    return SUCCESS;
-}
-
-static err_t sock_test_read (struct sock_stream *base_sock, void *buf_ptr, size_t *len, struct error_info *err)
-{
-    struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
-    struct io_buf *buf = &sock->recv_buf;
-    struct io_vec *vec = buf->read_vec;
-    
-    // EOF/nonblock if we're past the end of the last vector
-    if (!vec || vec == buf->vecs + buf->count || buf->off >= vec->len) {
-        if (sock->nonblocking && !sock->eof) {
-            // wait for more to be fed in
-            *len = 0;
-            return SUCCESS;
-
-        } else {
-            // EOF!
-            return SET_ERROR(err, ERR_READ_EOF);
-        }
-    }
-    
-    // amount of data available in this iovec
-    size_t available = vec->len - buf->off;
-
-    // amount to read
-    size_t to_read = *len;
-    
-    // trim down?
-    if (to_read > available)
-        to_read = available;
-
-    // copy
-    memcpy(buf_ptr, vec->buf + buf->off, to_read);
-    
-    // consumed the whole vec?
-    if (to_read < available) {
-        // move offset
-        buf->off += to_read;
-
-    } else {
-        // next vector
-        buf->read_vec++;
-    }
-
-    // update len
-    *len = to_read;
-
-    // ok
-    return SUCCESS;
-}
-
-static err_t sock_test_write (struct sock_stream *base_sock, const void *buf_ptr, size_t *len, struct error_info *err)
-{
-    struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
-    struct io_buf *buf = &sock->send_buf;
-
-    // ensure there's room
-    if ((ERROR_CODE(err) = sock_test_grow_buf(buf)))
-        goto error;
-    
-    // the next buffer
-    struct io_vec *vec = buf->write_vec;
-
-    // store
-    vec->len = *len;
-    assert((vec->buf = malloc(vec->len)));
-    memcpy(vec->buf, buf_ptr, vec->len);
-
-    // move vec onwards
-    buf->write_vec++;
-
-    // ok
-    return SUCCESS;
-
-error:
-    return ERROR_CODE(err);
-}
-
-static err_t sock_test_event_init (struct sock_stream *base_sock)
-{
-    struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
-
-    // set the nonblocking flag
-    sock->nonblocking = true;
-
-    return SUCCESS;
-}
-
-static err_t sock_test_event_enable (struct sock_stream *base_sock, short mask)
-{
-    struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
-
-    // store mask
-    sock->ev_mask = mask;
-
-    return SUCCESS;
-}
-
-static void sock_test_release (struct sock_stream *base_sock)
-{
-    struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
-
-    sock_test_destroy(sock);
-}
-
-/*
- * Our sock_stream_type
- */
-static struct sock_stream_type sock_test_type = {
-    .methods                = {
-        .read               = &sock_test_read,
-        .write              = &sock_test_write,
-        .event_init         = &sock_test_event_init,
-        .event_enable       = &sock_test_event_enable,
-        .release            = &sock_test_release,
-    },
-};
-
-struct sock_test* sock_test_create (void)
-{
-    struct sock_test *sock;
-
-    // allocate
-    assert((sock = calloc(1, sizeof(*sock))));
-    
-    // initialize base with our sock_stream_type
-    sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type, NULL, NULL);
-
-    // ok
-    return sock;
-}
-
-void sock_test_destroy (struct sock_test *sock)
-{
-    size_t i;
-    struct io_buf *sbuf = &sock->send_buf, *rbuf = &sock->recv_buf;
-    
-    // free the send buffer
-    for (i = 0; i < sbuf->count; i++) {
-        free(sbuf->vecs[i].buf);
-    }
-
-    // free the buffer vector lists
-    free(sbuf->vecs);
-    free(rbuf->vecs);
-    
-    // free the sock itself
-    free(sock);
-}
-
-void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count, bool eof)
-{
-    struct io_buf *buf = &sock->recv_buf;
-
-    // allocate + copy
-    assert((buf->vecs = calloc(count, sizeof(struct io_vec))));
-    memcpy(buf->vecs, vecs, count * sizeof(struct io_vec));
-    
-    // set
-    buf->count = count;
-    buf->read_vec = buf->vecs;
-    buf->write_vec = buf->vecs + count;
-    buf->off = 0;
-    
-    // set EOF flag?
-    if (eof)
-        sock->eof = true;
-}
-
-void sock_test_notify_events (struct sock_test *sock)
-{
-    // notify if events are enabled
-    if (sock->ev_mask) {
-        // zero mask
-        int mask = sock->ev_mask;
-        sock->ev_mask = 0;
-
-        sock_stream_invoke_callbacks(SOCK_TEST_BASE(sock), mask);
-    }
-}
-
-void sock_test_add_recv_vec (struct sock_test *sock, struct io_vec new_vec)
-{
-    struct io_buf *buf = &sock->recv_buf;
-
-    // ensure there's room
-    assert(sock_test_grow_buf(buf) == SUCCESS);
-    
-    // copy    
-    *(buf->write_vec++) = new_vec;
-    
-    // notify
-    sock_test_notify_events(sock);
-}
-
-void sock_test_add_recv_str (struct sock_test *sock, const char *str)
-{
-    struct io_vec vec = {
-        (char*) str, strlen(str)
-    };
-
-    sock_test_add_recv_vec(sock, vec);
-}
-
-void sock_test_set_recv_eof (struct sock_test *sock)
-{
-    sock->eof = true;
-
-    sock_test_notify_events(sock);
-}
-
-void sock_test_get_send_data (struct sock_test *sock, char **buf_ptr, size_t *len_ptr)
-{
-    struct io_buf *buf = &sock->send_buf;
-    size_t len = 0, i, off = 0;
-    char *out;
-    
-    // calculate total size
-    for (i = 0; i < buf->count; i++) {
-        len += buf->vecs[i].len;
-    }
-
-    // alloc
-    assert((out = malloc(len)));
-
-    // copy
-    for (i = 0; i < buf->count; i++) {
-        struct io_vec *vec = buf->vecs + i;
-
-        memcpy(out + off, vec->buf, vec->len);
-        off += vec->len;
-        
-        // zero
-        free(vec->buf); vec->buf = NULL;
-        vec->len = 0;
-    }
-    
-    // update return
-    *buf_ptr = out;
-    *len_ptr = len;
-
-    // update write_vec
-    buf->write_vec = buf->vecs;
-}
-
--- a/src/sock_test.h	Sun May 03 17:18:16 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-#ifndef SOCK_TEST_H
-#define SOCK_TEST_H
-
-/**
- * @file
- *
- * Dummy sock_stream implemention for local testing.
- */
-#include "sock_internal.h"
-#include <stdbool.h>
-
-/**
- * Simple IO vector
- */
-struct io_vec {
-    /** The buffer */
-    char *buf;
-
-    /** Buffer size */
-    size_t len;
-};
-
-/**
- * Simple vectored IO-buffer
- */
-struct io_buf {
-    /** The array of buffer-vectors, {NULL}-terminated */
-    struct io_vec *vecs;
-
-    /** The number of io_vecs */
-    size_t count;
-
-    /** Current read/write vector */
-    struct io_vec *read_vec, *write_vec;
-
-    /** Offset into current vector */
-    size_t off;
-};
-
-/**
- * A dummy sock_stream implementation intended for testing purposes.
- */
-struct sock_test {
-    /** The base struct for sock_stream_* functions */
-    struct sock_stream base;
-
-    /** The send/recieve buffers */
-    struct io_buf send_buf, recv_buf;
-
-    /** non-blocking mode? */
-    bool nonblocking;
-
-    /** No more data is going to be added, return EOF once all the rest is consumed */
-    bool eof;
-
-    /** event flags */
-    int ev_mask;
-};
-
-/**
- * Get a sock_stream pointer from a sock_tcp pointer
- */
-#define SOCK_TEST_BASE(sock_ptr) (&(sock_ptr)->base)
-
-/**
- * Get the sock_stream.err pointer from a sock_tcp pointer
- */
-#define SOCK_TEST_ERR(sock_ptr) SOCK_ERR(SOCK_TEST_BASE(sock_ptr))
-
-/**
- * A dummy stream socket intended for testing purposes.
- */
-struct sock_test* sock_test_create (void);
-
-/**
- * Destroy the sock buffer, releasing any resource we allocated ourself
- */
-void sock_test_destroy (struct sock_test *sock);
-
-/**
- * Set the recieve buffer contents.
- *
- * The vectors themselves are copied, but the data they contain is not.
- *
- * If the EOF flag is given, it indicates that no more data will be added, otherwise the eof status is unchanged.
- */
-void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count, bool eof);
-
-/**
- * Add some data to the recieve buffer.
- *
- * If events are enabled, they are triggered.
- */
-void sock_test_add_recv_vec (struct sock_test *sock, struct io_vec vec);
-
-/**
- * Add a string to the recieve buffer using sock_test_add_recv_vec()
- */
-void sock_test_add_recv_str (struct sock_test *sock, const char *str);
-
-/**
- * Set EOF on recv, and trigger events.
- */
-void sock_test_set_recv_eof (struct sock_test *sock);
-
-/**
- * Get the send buffer contents as a single string, free() after use if you care about that.
- *
- * Clears the send buffer, so this doesn't return the same data twice.
- */
-void sock_test_get_send_data (struct sock_test *sock, char **buf, size_t *len);
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/transport_test.c	Sun May 03 17:19:05 2009 +0300
@@ -0,0 +1,358 @@
+#include "transport_test.h"
+#include "transport_internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+/**
+ * Simple IO vector
+ */
+struct io_vec {
+    /** The buffer */
+    char *buf;
+
+    /** Buffer size */
+    size_t len;
+};
+
+/**
+ * Simple vectored IO-buffer
+ */
+struct io_buf {
+    /** The array of buffer-vectors, {NULL}-terminated */
+    struct io_vec *vecs;
+
+    /** The number of io_vecs */
+    size_t count;
+
+    /** Current read/write vector */
+    struct io_vec *read_vec, *write_vec;
+
+    /** Offset into current vector */
+    size_t off;
+};
+
+/**
+ * Forward-declare our transport_type
+ */
+extern const struct transport_type transport_test_type;
+
+
+/**
+ * A dummy sock_stream implementation intended for testing purposes.
+ */
+struct transport_test {
+    /** The base transport stuff */
+    struct transport base;
+
+    /** The send/recieve buffers */
+    struct io_buf send_buf, recv_buf;
+
+    /** No more data is going to be added, return EOF once all the rest is consumed */
+    bool eof;
+};
+
+/**
+ * Get a transport pointer from a transport_test pointer
+ */
+#define TRANSPORT_TEST_BASE(tp_ptr) (&(tp_ptr)->base)
+
+/**
+ * Grow buf->vecs if needed to ensure that buf->write_vec points to a valid io_vec
+ */
+static err_t io_buf_grow (struct io_buf *buf)
+{
+    size_t read_vec_offset = buf->read_vec ? (buf->read_vec - buf->vecs) : 0;
+    size_t write_vec_offset = buf->write_vec ? (buf->write_vec - buf->vecs) : 0;
+    struct io_vec *v;
+    struct io_vec *vecs_tmp = buf->vecs;
+
+    // don't grow if not full
+    if (buf->vecs && buf->write_vec < buf->vecs + buf->count)
+        return SUCCESS;
+
+    // new size
+    buf->count = buf->count * 2 + 1;
+
+    // grow
+    if ((buf->vecs = realloc(buf->vecs, buf->count * sizeof(struct io_vec))) == NULL) {
+        // restore old value
+        buf->vecs = vecs_tmp;
+
+        return ERR_CALLOC;
+    }
+
+    // restore vec positions
+    buf->write_vec = buf->vecs + write_vec_offset;
+    buf->read_vec = buf->vecs + read_vec_offset;
+
+    // zero new vecs
+    for (v = buf->write_vec; v < buf->vecs + buf->count; v++)
+        memset(v, 0, sizeof(*v));
+
+    // ok
+    return SUCCESS;
+}
+
+/**
+ * Write some data to an io_buf, copying it.
+ */
+static err_t io_buf_write (struct io_buf *buf, const char *data, size_t len)
+{
+    error_t err;
+
+    // ensure there's room
+    if ((ERROR_CODE(&err) = io_buf_grow(buf)))
+        goto error;
+    
+    // the vector to use
+    struct io_vec *vec = buf->write_vec;
+
+    // allocate
+    if ((vec->buf = malloc(len)) == NULL)
+        JUMP_SET_ERROR(&err, ERR_MEM);
+    
+    // store
+    vec->len = len;
+    memcpy(vec->buf, data, len);
+
+    // vec consumed
+    buf->write_vec++;
+
+    // ok
+    return SUCCESS;
+
+error:
+    return ERROR_CODE(&err);
+}
+
+/**
+ * Destroy the io_buf, freeing all resources.
+ *
+ * The io_buf must not be used anymore.
+ */
+static void io_buf_destroy (struct io_buf *buf)
+{
+    size_t i;
+
+    // free the io_vec buffers
+    for (i = 0; i < buf->count; i++) {
+        free(buf->vecs[i].buf);
+    }
+    
+    // free the vector list
+    free(buf->vecs);
+}
+
+/**
+ * transport_methods::read implementation.
+ */
+static err_t transport_test_read (transport_t *transport, void *buf_ptr, size_t *len, error_t *err)
+{
+    struct transport_test *tp = transport_check(transport, &transport_test_type);
+    struct io_buf *buf = &tp->recv_buf;
+    struct io_vec *vec = buf->read_vec;
+    
+    // EOF/nonblock if we're past the end of the last vector
+    if (!vec || vec == buf->vecs + buf->count || buf->off >= vec->len) {
+        if (!tp->eof) {
+            // wait for more to be fed in
+            *len = 0;
+            return SUCCESS;
+
+        } else {
+            // EOF!
+            return SET_ERROR(err, ERR_EOF);
+        }
+    }
+    
+    // amount of data available in this iovec
+    size_t available = vec->len - buf->off;
+
+    // amount to read
+    size_t to_read = *len;
+    
+    // trim down?
+    if (to_read > available)
+        to_read = available;
+
+    // copy
+    memcpy(buf_ptr, vec->buf + buf->off, to_read);
+    
+
+    if (to_read < available) {
+        // bytes still left in the vector
+        buf->off += to_read;
+
+    } else {
+        // consumed the whole vector
+        // XXX: release data?
+        buf->read_vec++;
+        buf->off = 0;
+    }
+
+    // update len
+    *len = to_read;
+
+    // ok
+    return SUCCESS;
+}
+
+/**
+ * transport_methods::write implementation.
+ */
+static err_t transport_test_write (transport_t *transport, const void *data, size_t *len, error_t *err)
+{
+    struct transport_test *tp = transport_check(transport, &transport_test_type);
+
+    // write it out
+    // XXX: partial writes?
+    if ((ERROR_CODE(err) = io_buf_write(&tp->send_buf, data, *len)))
+        goto error;
+    
+    // ok
+    return SUCCESS;
+
+error:
+    return ERROR_CODE(err);
+}
+
+static err_t transport_test_events (transport_t *transport, short mask, error_t *err)
+{
+    struct transport_test *tp = transport_check(transport, &transport_test_type);
+
+    (void) tp;
+    (void) mask;
+    (void) err;
+    
+    // XXX: don't re-trigger anything
+    
+    return SUCCESS;
+}
+
+static void _transport_test_destroy (transport_t *transport)
+{
+    struct transport_test *tp = transport_check(transport, &transport_test_type);
+
+    transport_test_destroy(tp);
+}
+
+/*
+ * Our sock_stream_type
+ */
+const struct transport_type transport_test_type = {
+    .methods                = {
+        .read               = transport_test_read,
+        .write              = transport_test_write,
+        .events             = transport_test_events,
+        .destroy            = _transport_test_destroy
+    },
+};
+
+struct transport_test* transport_test_create (struct transport_info *info)
+{
+    struct transport_test *tp;
+
+    // allocate
+    assert((tp = calloc(1, sizeof(*tp))));
+    
+    // initialize base with our transport_type
+    transport_init(TRANSPORT_TEST_BASE(tp), &transport_test_type, info);
+
+    // ok
+    return tp;
+}
+
+transport_t* transport_test_cast (struct transport_test *tp)
+{
+    return TRANSPORT_TEST_BASE(tp);
+}
+
+void transport_test_event (struct transport_test *tp, short what)
+{
+    // invoke, masking out as needed
+    // this won't do anything if all the bits are masked out
+    transport_invoke(TRANSPORT_TEST_BASE(tp), what & TRANSPORT_TEST_BASE(tp)->info.ev_mask);
+}
+
+void transport_test_push_buf (struct transport_test *tp, const char *data, size_t len)
+{
+    // push it
+    assert(io_buf_write(&tp->recv_buf, data, len) == SUCCESS);
+    
+    // notify
+    transport_test_event(tp, TRANSPORT_READ);
+}
+
+void transport_test_push_str (struct transport_test *tp, const char *str)
+{
+    // push it
+    transport_test_push_buf(tp, str, strlen(str));
+}
+
+void transport_test_push_fmt (struct transport_test *tp, const char *fmt, ...)
+{
+    char buf[TRANSPORT_TEST_FMT_MAX];
+    size_t ret;
+
+    // format
+    va_list vargs; va_start(vargs, fmt);
+    assert((ret = vsnprintf(buf, sizeof(buf), fmt, vargs)) <= sizeof(buf));
+    va_end(vargs);
+       
+    // push it
+    transport_test_push_buf(tp, buf, ret);
+}
+
+void transport_test_push_eof (struct transport_test *tp)
+{
+    // update state
+    tp->eof = true;
+
+    transport_test_event(tp, TRANSPORT_READ);
+}
+
+void transport_test_pull_buf (struct transport_test *tp, char **buf_ptr, size_t *len_ptr)
+{
+    struct io_buf *buf = &tp->send_buf;
+    size_t len = 0, i, off = 0;
+    char *out;
+    
+    // calculate total size
+    for (i = 0; i < buf->count; i++) {
+        len += buf->vecs[i].len;
+    }
+
+    // alloc
+    assert((out = malloc(len)));
+
+    // copy
+    for (i = 0; i < buf->count; i++) {
+        struct io_vec *vec = buf->vecs + i;
+
+        memcpy(out + off, vec->buf, vec->len);
+        off += vec->len;
+        
+        // zero
+        free(vec->buf); vec->buf = NULL;
+        vec->len = 0;
+    }
+    
+    // update return
+    *buf_ptr = out;
+    *len_ptr = len;
+
+    // update write_vec
+    buf->write_vec = buf->vecs;
+}
+
+void transport_test_destroy (struct transport_test *tp)
+{
+    // free the buffers
+    io_buf_destroy(&tp->send_buf);
+    io_buf_destroy(&tp->recv_buf);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/transport_test.h	Sun May 03 17:19:05 2009 +0300
@@ -0,0 +1,74 @@
+#ifndef TRANSPORT_TEST_H
+#define TRANSPORT_TEST_H
+
+/**
+ * @file
+ *
+ * Dummy transport implemention for local testing.
+ */
+#include "transport.h"
+
+/**
+ * The opaque transport state
+ */
+struct transport_test;
+
+/**
+ * Construct a new, empty, connected transport_test.
+ */
+struct transport_test* transport_test_create (struct transport_info *info);
+
+/**
+ * A transport_test is a valid transport, this performs the cast
+ */
+transport_t* transport_test_cast (struct transport_test *tp);
+
+/**
+ * Invoke the transport's user callbacks for the given event mask, unless masked out.
+ */
+void transport_test_event (struct transport_test *tp, short what);
+
+/**
+ * Adds a data buffer to the recieve buffer.
+ *
+ * The given data is copied.
+ *
+ * If events are enabled, they are triggered.
+ */
+void transport_test_push_buf (struct transport_test *tp, const char *buf, size_t len);
+
+/**
+ * Add a string to the recieve buffer using transport_test_push_buf()
+ */
+void transport_test_push_str (struct transport_test *tp, const char *str);
+
+/**
+ * Maximum length of a formatted string pushed
+ */
+#define TRANSPORT_TEST_FMT_MAX 4096
+
+/**
+ * Add a formatted string to the recieve buffer
+ *
+ * @see TRANSPORT_TEST_FMT_MAX
+ */
+void transport_test_push_fmt (struct transport_test *tp, const char *fmt, ...);
+
+/**
+ * Set EOF on recv.
+ */
+void transport_test_push_eof (struct transport_test *tp);
+
+/**
+ * Get the send buffer contents as a single buffer, free() after use.
+ *
+ * This clears the send buffer, so this doesn't return the same data twice.
+ */
+void transport_test_pull_buf (struct transport_test *tp, char **buf_ptr, size_t *len_ptr);
+
+/**
+ * Destroy the transport buffer, releasing any buffers we allocated ourself
+ */
+void transport_test_destroy (struct transport_test *tp);
+
+#endif /* TRANSPORT_TEST_H */