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