src/transport.c
author Tero Marttila <terom@fixme.fi>
Wed, 27 May 2009 23:57:48 +0300
branchnew-lib-errors
changeset 217 7728d6ec3abf
parent 183 7bfbe9070c50
permissions -rw-r--r--
nexus.c compiles
#include "transport_internal.h"

#include <assert.h>

/**
 * 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, -1);

    // 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);

    // XXX: not writeable
    if (!type->methods.write)
        return SET_ERROR(err, -1);

    // 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);
}