terom@1: #ifndef SOCK_H terom@1: #define SOCK_H terom@1: terom@34: /** terom@34: * @file terom@34: * terom@1: * Low-level socket-related functions terom@1: */ terom@3: #include "error.h" terom@1: #include terom@9: #include terom@1: terom@34: /** terom@34: * The generic stream socket handle terom@1: */ terom@1: struct sock_stream; terom@1: terom@34: /** terom@85: * Callback for connect_async completion notification. If err is NULL, the connection completed succesfully, terom@85: * otherwise, it failed. terom@85: */ terom@85: typedef void (*sock_stream_connect_cb) (struct sock_stream *sock, struct error_info *err, void *arg); terom@85: terom@85: /** terom@9: * Async callbacks for socket operation terom@9: */ terom@9: struct sock_stream_callbacks { terom@85: /** Socket is readable */ terom@85: void (*on_read) (struct sock_stream *sock, void *arg); terom@9: terom@34: /** Socket is writeable */ terom@85: void (*on_write) (struct sock_stream *sock, void *arg); terom@9: }; terom@9: terom@34: /** terom@34: * Socket function error codes terom@34: */ terom@30: enum sock_error_code { terom@30: _ERR_SOCK_BEGIN = _ERR_SOCK, terom@30: ERR_SOCKET, terom@30: terom@85: /** connect() error, either direct or async */ terom@30: ERR_CONNECT, terom@30: ERR_READ, terom@30: terom@30: /** EOF on read() */ terom@30: ERR_READ_EOF, terom@30: ERR_WRITE, terom@30: terom@30: /** EOF on write() */ terom@30: ERR_WRITE_EOF, terom@30: ERR_FCNTL, terom@30: terom@30: /** Lingering error on close() */ terom@30: ERR_CLOSE, terom@85: ERR_GETSOCKOPT, terom@30: }; terom@30: terom@34: /** terom@3: * Initialize the socket module's global state. Call this before calling any other sock_* functions. terom@9: * terom@9: * The given \a ev_base is the libevent base to use for nonblocking operation. terom@34: * terom@34: * @param ev_base the libevent base to use for events terom@34: * @param err returned error info terom@3: */ terom@9: err_t sock_init (struct event_base *ev_base, struct error_info *err); terom@3: terom@34: /** terom@85: * A simple TCP connect to the given host/service, using getaddrinfo. The connected socket is returned via *sock_ptr. terom@85: * In case of errors, additional error information is stored in *err. terom@3: * terom@34: * @param sock_ptr the new sock_stream terom@34: * @param host the hostname to connect to terom@34: * @param service the service name (i.e. port) to connect to terom@34: * @param err returned error info terom@1: */ terom@3: err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err); terom@1: terom@40: /** terom@85: * Start a non-blocking TCP connect to the given host/service. The socket will not yet be connected once the function terom@85: * returns, but rather, the readyness of the socket will be indicated later using the given \a cb_func. terom@85: * terom@85: * Note that currently it is an error to call sock_stream_event_init before the cb_func has been called. terom@85: * terom@85: * XXX: blocking DNS resolution terom@85: * terom@85: * @param sock_ptr the new sock_stream terom@85: * @param host the hostname to connect to terom@85: * @param service the service name (i.e. port) to connect to terom@85: * @param cb_func the callback used to handle the result of the async operation terom@85: * @param cb_arg opaque context argument passed back to cb_func terom@85: * @param err returned error info terom@85: */ terom@85: err_t sock_tcp_connect_async (struct sock_stream **sock_ptr, const char *host, const char *service, terom@85: sock_stream_connect_cb cb_func, void *cb_arg, struct error_info *err); terom@85: terom@85: /** terom@5: * A simple blocking SSL connect to the given host/service. The connected/handshake'd SSL socket is returned via terom@5: * *sock_ptr. In case of errors, additional error information is stored in *err. terom@1: * terom@34: * @param sock_ptr the new sock_stream terom@34: * @param host the hostname to connect to terom@34: * @param service the TCP service name (i.e. port) to connect to terom@34: * @param err returned error info terom@34: * terom@1: * XXX: blocking terom@1: * XXX: doesn't do any certificate verification. terom@1: */ terom@15: err_t sock_ssl_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err); terom@1: terom@34: /** terom@34: * Read a series of bytes from the socket into the given \a buf (up to \a len bytes). If succesfull, this returns terom@34: * the number of bytes read (which will be less than or equal to \a len). If the socket is nonblocking (i.e. terom@34: * sock_stream_event_init() was set), and there is no data available, this returns zero, and one should use terom@34: * sock_stream_event_enable() to wait for more data. terom@34: * terom@34: * On errors, this returns the negative err_t code, and the specific error information can be accessed using terom@34: * sock_stream_error().. terom@34: * terom@34: * @param sock the socket to read the bytes from terom@34: * @param buf the byte buffer to write the bytes into terom@34: * @param len the number of bytes to read into the buffer terom@34: * @return bytes read, zero if none available, -err_t terom@9: */ terom@10: int sock_stream_read (struct sock_stream *sock, void *buf, size_t len); terom@34: terom@34: /** terom@34: * Write a series of bytes from the given \a buf (containing \a len bytes) to the socket. If succesfull, this returns terom@34: * the number of bytes written (which may be less than \a len if the OS write buffer was full). If the socket is terom@34: * nonblocking (i.e. sock_stream_event_init() was set), and the operation would have blocked, no data was written, and terom@34: * this returns zero, and one should use sock_stream_event_enable() to retry. terom@34: * terom@34: * On errors, this returns the negative err_t code, and the specific error information can be accessed using terom@34: * sock_stream_error(). terom@34: * terom@34: * @param sock the socket to write the bytes to terom@34: * @param buf the byte buffer terom@34: * @param len number of bytes to write terom@34: * @return bytes written, zero if would have blocked, -err_t terom@34: */ terom@10: int sock_stream_write (struct sock_stream *sock, const void *buf, size_t len); terom@9: terom@34: /** terom@10: * Initialize event-based operation for this sock_stream. This will set the stream into nonblocking mode, and the given terom@10: * callbacks will be fired once enabled using sock_stream_event_enable(). terom@10: * terom@10: * Note that the callbacks struct isn't copied - it's used as-is-given. terom@34: * terom@34: * @param sock the socket to set up for nonblocking operation terom@34: * @param callbacks the on_read/on_write callbacks to invoke terom@34: * @param arg the context argument for the callbacks terom@1: */ terom@10: err_t sock_stream_event_init (struct sock_stream *sock, const struct sock_stream_callbacks *callbacks, void *arg); terom@10: terom@34: /** terom@34: * Enable some events for this sock, as set up earlier with event_init. Mask should contain EV_READ/EV_WRITE. terom@10: * terom@12: * The implementation of this is slightly hazy for complex protocols; this should only be used to map from terom@12: * sock_stream_read/write to the corresponding sock_stream_callback. That is, if sock_stream_read returns zero, then terom@34: * call event_enable(EV_READ), wherepon on_read will later be called. Other operations (such as calling terom@34: * sock_stream_write with *different* data after it once returns zero) might result in errors. terom@10: */ terom@10: err_t sock_stream_event_enable (struct sock_stream *sock, short mask); terom@3: terom@3: /** terom@8: * Get current error_info for \a sock. terom@3: */ terom@8: const struct error_info* sock_stream_error (struct sock_stream *sock); terom@1: terom@28: /** terom@28: * Close and release the given socket, ignoring errors. It must not be used anymore after this. terom@28: * terom@28: * This is intended to be used to abort in case of errors, and does not close the connection cleanly. terom@28: */ terom@28: void sock_stream_release (struct sock_stream *sock); terom@28: terom@1: #endif