src/lib/transport.c
branchnew-lib-errors
changeset 219 cefec18b8268
parent 183 7bfbe9070c50
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/transport.c	Thu May 28 01:17:36 2009 +0300
@@ -0,0 +1,160 @@
+#include "transport_internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+const struct error_list transport_errors = ERROR_LIST("transport",
+    ERROR_TYPE(         ERR_TRANSPORT_EOF,              "EOF"                       ),
+    ERROR_TYPE(         ERR_TRANSPORT_READABLE,         "transport not readable"    ),
+    ERROR_TYPE(         ERR_TRANSPORT_WRITEABLE,        "transport not writeable"   )
+);
+
+/**
+ * Our own object_type
+ */
+const struct object_type transport_type_type = {
+    .parent     = NULL,
+};
+
+/*
+ * Internal API
+ */
+void transport_init (transport_t *transport, const struct transport_type *type, const struct transport_info *info)
+{
+    // init object
+    object_init(&transport->base_obj, &type->base_type);
+    
+    // store
+    if (info)
+        transport->info = *info;
+}
+
+void* transport_check (transport_t *transport, const struct transport_type *type)
+{
+    // trip as a bug
+    assert(object_check(&transport->base_obj, &type->base_type));
+
+    // ok, cast via void*
+    return transport;
+}
+
+void transport_connected (transport_t *transport, const error_t *err, bool direct)
+{
+    const struct transport_type *type = object_type(&transport->base_obj, &transport_type_type);
+
+    if (direct || !type->methods._connected) {
+        // user callback
+        if (err) {
+            // connect failed
+            transport->info.cb_tbl->on_error(transport, err, transport->info.cb_arg);
+
+        } else {
+            // update state
+            transport->connected = true;
+
+            // connect succesfull
+            transport->info.cb_tbl->on_connect(transport, transport->info.cb_arg);
+        }
+
+    } else {
+        // wrapper method
+        type->methods._connected(transport, err);
+
+    }
+}
+
+void transport_invoke (transport_t *transport, short what)
+{
+    // on_ready
+    if (what & TRANSPORT_READ && transport->info.cb_tbl->on_read)
+        transport->info.cb_tbl->on_read(transport, transport->info.cb_arg);
+
+    // on_write
+    if (what & TRANSPORT_WRITE && transport->info.cb_tbl->on_write)
+        transport->info.cb_tbl->on_write(transport, transport->info.cb_arg);
+
+}
+
+void transport_error (transport_t *transport, const error_t *err)
+{
+    // update state
+    transport->connected = false;
+
+    // invoke callback
+    transport->info.cb_tbl->on_error(transport, err, transport->info.cb_arg);
+}
+
+/*
+ * Public API
+ */
+int transport_read (transport_t *transport, void *buf, size_t len, error_t *err)
+{
+    const struct transport_type *type = object_type(&transport->base_obj, &transport_type_type);
+
+    // not readable
+    if (!type->methods.read)
+        return SET_ERROR(err, &transport_errors, ERR_TRANSPORT_READABLE);
+
+    // proxy off to method handler
+    if (type->methods.read(transport, buf, &len, err))
+        return -error_code(err);
+    
+    // return updated 'bytes-read' len
+    return len;
+}
+
+int transport_write (transport_t *transport, const void *buf, size_t len, error_t *err)
+{
+    const struct transport_type *type = object_type(&transport->base_obj, &transport_type_type);
+
+    // not writeable
+    if (!type->methods.write)
+        return SET_ERROR(err, &transport_errors, ERR_TRANSPORT_WRITEABLE);
+
+    // proxy off to method handler
+    if (type->methods.write(transport, buf, &len, err))
+        return -error_code(err);
+
+    // return updated 'bytes-written' len
+    return len;
+}
+
+err_t transport_events (transport_t *transport, short mask)
+{
+    const struct transport_type *type = object_type(&transport->base_obj, &transport_type_type);
+    error_t err;
+
+    // notify transport
+    if (type->methods.events) {
+        if (type->methods.events(transport, mask, &err))
+            goto error;
+    }
+
+    // update the event mask
+    transport->info.ev_mask = mask;
+
+    // ok
+    return SUCCESS;
+
+error:
+    return ERROR_CODE(&err);
+}
+
+void transport_set_callbacks (transport_t *transport, const struct transport_callbacks *cb_tbl, void *cb_arg)
+{
+    transport->info.cb_tbl = cb_tbl;
+    transport->info.cb_arg = cb_arg;
+}
+
+void transport_destroy (transport_t *transport)
+{
+    const struct transport_type *type = object_type(&transport->base_obj, &transport_type_type);
+
+    // destroy the transport-specific stuff
+    if (type->methods.deinit)
+        type->methods.deinit(transport);
+
+    // then the transport itself
+    free(transport);
+}
+