#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