--- 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 */