src/sock.h
author Tero Marttila <terom@fixme.fi>
Tue, 10 Mar 2009 19:52:38 +0200
changeset 34 763f65f9df0c
parent 30 7f8dd120933f
child 40 51678c7eae03
permissions -rw-r--r--
add doxygen.conf, and tweak comments
#ifndef SOCK_H
#define SOCK_H

/**
 * @file
 *
 * Low-level socket-related functions
 */
#include "error.h"
#include <sys/types.h>
#include <event2/event.h>

/**
 * The generic stream socket handle
 */
struct sock_stream;

/**
 * Async callbacks for socket operation
 */
struct sock_stream_callbacks {
    /** Sockeet is readable */
    void (*on_read)(struct sock_stream *sock, void *arg);

    /** Socket is writeable */
    void (*on_write)(struct sock_stream *sock, void *arg);
};

/**
 * Socket function error codes
 */
enum sock_error_code {
    _ERR_SOCK_BEGIN = _ERR_SOCK,
    
    /** socket() error */
    ERR_SOCKET,

    /** connect() error */
    ERR_CONNECT,

    /** read() error */
    ERR_READ,

    /** EOF on read() */
    ERR_READ_EOF,

    /** write() error */
    ERR_WRITE,

    /** EOF on write()  */
    ERR_WRITE_EOF,

    /** Error on fcntl() */
    ERR_FCNTL,

    /** Lingering error on close() */
    ERR_CLOSE,
};

/**
 * Initialize the socket module's global state. Call this before calling any other sock_* functions.
 *
 * The given \a ev_base is the libevent base to use for nonblocking operation.
 *
 * @param ev_base the libevent base to use for events
 * @param err returned error info
 */
err_t sock_init (struct event_base *ev_base, struct error_info *err);

/**
 * A simple blocking TCP connect to the given host/service, using getaddrinfo. The connected socket is returned via
 * *sock_ptr. In case of errors, additional error information is stored in *err.
 *
 * @param sock_ptr the new sock_stream
 * @param host the hostname to connect to
 * @param service the service name (i.e. port) to connect to
 * @param err returned error info
 *
 * XXX: blocking
 */
err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err);

/*
 * A simple blocking SSL connect to the given host/service. The connected/handshake'd SSL socket is returned via
 * *sock_ptr. In case of errors, additional error information is stored in *err.
 *
 * @param sock_ptr the new sock_stream
 * @param host the hostname to connect to
 * @param service the TCP service name (i.e. port) to connect to
 * @param err returned error info
 *
 * XXX: blocking
 * XXX: doesn't do any certificate verification.
 */
err_t sock_ssl_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err);

/**
 * Read a series of bytes from the socket into the given \a buf (up to \a len bytes). If succesfull, this returns
 * the number of bytes read (which will be less than or equal to \a len). If the socket is nonblocking (i.e.
 * sock_stream_event_init() was set), and there is no data available, this returns zero, and one should use
 * sock_stream_event_enable() to wait for more data.
 *
 * On errors, this returns the negative err_t code, and the specific error information can be accessed using
 * sock_stream_error()..
 *
 * @param sock the socket to read the bytes from
 * @param buf the byte buffer to write the bytes into
 * @param len the number of bytes to read into the buffer
 * @return bytes read, zero if none available, -err_t
 */
int sock_stream_read (struct sock_stream *sock, void *buf, size_t len);

/**
 * Write a series of bytes from the given \a buf (containing \a len bytes) to the socket. If succesfull, this returns
 * the number of bytes written (which may be less than \a len if the OS write buffer was full). If the socket is
 * nonblocking (i.e. sock_stream_event_init() was set), and the operation would have blocked, no data was written, and
 * this returns zero, and one should use sock_stream_event_enable() to retry.
 *
 * On errors, this returns the negative err_t code, and the specific error information can be accessed using
 * sock_stream_error().
 *
 * @param sock the socket to write the bytes to
 * @param buf the byte buffer
 * @param len number of bytes to write
 * @return bytes written, zero if would have blocked, -err_t
 */
int sock_stream_write (struct sock_stream *sock, const void *buf, size_t len);

/**
 * Initialize event-based operation for this sock_stream. This will set the stream into nonblocking mode, and the given
 * callbacks will be fired once enabled using sock_stream_event_enable().
 *
 * Note that the callbacks struct isn't copied - it's used as-is-given.
 *
 * @param sock the socket to set up for nonblocking operation
 * @param callbacks the on_read/on_write callbacks to invoke
 * @param arg the context argument for the callbacks
 */
err_t sock_stream_event_init (struct sock_stream *sock, const struct sock_stream_callbacks *callbacks, void *arg);

/**
 * Enable some events for this sock, as set up earlier with event_init. Mask should contain EV_READ/EV_WRITE.
 *
 * The implementation of this is slightly hazy for complex protocols; this should only be used to map from
 * sock_stream_read/write to the corresponding sock_stream_callback. That is, if sock_stream_read returns zero, then
 * call event_enable(EV_READ), wherepon on_read will later be called. Other operations (such as calling
 * sock_stream_write with *different* data after it once returns zero) might result in errors.
 */
err_t sock_stream_event_enable (struct sock_stream *sock, short mask);

/**
 * Get current error_info for \a sock.
 */
const struct error_info* sock_stream_error (struct sock_stream *sock);

/**
 * Close and release the given socket, ignoring errors. It must not be used anymore after this.
 *
 * This is intended to be used to abort in case of errors, and does not close the connection cleanly.
 */
void sock_stream_release (struct sock_stream *sock);

#endif