#ifndef TRANSPORT_INTERNAL_H
#define TRANSPORT_INTERNAL_H
/**
* @file
*
* The internal interface for transport implementations.
*/
#include "transport.h"
#include "object.h"
#include <stdbool.h>
/**
* The object_type for a transport_type
*/
extern const struct object_type transport_type_type;
/**
* The definition of a transport type
*/
struct transport_type {
struct object_type base_type;
/**
* Method table for implementation stuff.
*
* Note that it is the transport's resposibility to implement the behaviour described in transport.h
*/
struct transport_methods {
/** For transport_read() */
err_t (*read) (transport_t *transport, void *buf, size_t *len, error_t *err);
/** For transport_write() */
err_t (*write) (transport_t *transport, const void *buf, size_t *len, error_t *err);
/**
* The mask of event flags will be set to the given mask if this method is succesfull.
*
* The old mask is still available in transport::info::ev_mask.
*/
err_t (*events) (transport_t *transport, short mask, error_t *err);
/**
* Release the transport's internal state, but not the transport itself.
*
* In other words, this should release everything inside the transport_t, but not free() the transport_t itself.
*/
void (*deinit) (transport_t *transport);
/**
* Used by layered transports to handle transport_connected.
*
* If this is NULL, transport_connected will call the user callback directly, otherwise, it will proxy through this.
*
* The \a err param follows the same rules as for transport_connected() - NULL for success, error info otherwise.
*
* @param transport the transport state
* @param err error info if the connect failed
*/
void (*_connected) (transport_t *transport, const error_t *err);
} methods;
};
/**
* The base transport type
*/
struct transport {
struct object base_obj;
/** User info */
struct transport_info info;
/** Are we connected? */
bool connected;
};
/**
* Bind the given transport to the given type with the given user info.
*
* \a info may be given as NULL to not have any callbacks, but this will crash if any transport_* is called before
* transport_set_callbacks().
*
* It is a bug to call this with a transport that is already bound.
*/
void transport_init (transport_t *transport, const struct transport_type *type, const struct transport_info *info);
/**
* Check the type of the transport, and return the transport as a void* suitable for casting to the appropriate struct
* for the type, or any of its children.
*
* It is a bug to call this with a transport of a different type.
*/
void* transport_check (transport_t *transport, const struct transport_type *type);
/**
* Mark the transport as connected, calling transport_methods::_connected if it exists and \a direct is not given,
* transport_callbacks::on_connected/transport_callbacks::on_error otherwise.
*
* If the connect succeeded, \a err should be given as NULL. If the connect failed, \a err should contain the error
* info.
*
* If called from the transport_methods::_connected method, pass in direct to avoid recursion.
*
* This sets the transport::connected flag before calling transport_callbacks::on_connected (i.e. directly) without any
* error set.
*
* XXX: implement proper layering of types by taking a transport_type arg and chaining down from there.
*
* @param transport the transport state
* @param err NULL for success, otherwise connect error code
* @param direct call the user callback directly, ignoring any method
*/
void transport_connected (transport_t *transport, const error_t *err, bool direct);
/**
* Invoke the user callbacks based on the given TRANSPORT_* flags
*/
void transport_invoke (transport_t *transport, short what);
/**
* Mark the transport as failed, calling transport_methods::on_error with the given error code.
*/
void transport_error (transport_t *transport, const error_t *err);
#endif /* TRANSPORT_INTERNAL_H */