src/transport_internal.h
author Tero Marttila <terom@fixme.fi>
Sun, 03 May 2009 17:18:16 +0300
branchnew-transport
changeset 165 b3e95108c884
parent 159 d3e253d7281a
child 176 6750d50ee8cd
permissions -rw-r--r--
fix doc things
#ifndef TRANSPORT_INTERNAL_H
#define TRANSPORT_INTERNAL_H

/**
 * @file
 *
 * The internal interface for transport implementations.
 */ 
#include "transport.h"

#include <stdbool.h>

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

/**
 * The definition of a transport type
 */
struct transport_type {
    /** Parent type */
    const struct transport_type *parent;

    /** Method table */
    struct transport_methods methods;
};

/**
 * The base transport type
 */
struct transport {
    /** The type info, or NULL if not yet bound */
    const struct transport_type *type;

    /** 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.
 *
 * XXX: This sets the transport::connected flag, regardless of which callback it invokes.
 *
 * 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 */