Skip to content

Instantly share code, notes, and snippets.

@ry
Created May 12, 2011 02:05

Revisions

  1. ry created this gist May 12, 2011.
    271 changes: 271 additions & 0 deletions wu.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,271 @@
    /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to
    * deal in the Software without restriction, including without limitation the
    * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    * sell copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    * IN THE SOFTWARE.
    */

    #ifndef WU_H
    #define WU_H

    #define WU_VERSION_MAJOR 0
    #define WU_VERSION_MINOR 1

    #include <stdint.h> /* int64_t */
    #include <sys/types.h> /* size_t */

    typedef struct wu_err_s wu_err_t;
    typedef struct wu_handle_s wu_handle_t;
    typedef struct wu_req_s wu_req_t;


    #if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
    # include "wu-unix.h"
    #else
    # include "wu-win.h"
    #endif


    /* The status parameter is 0 if the request completed successfully,
    * and should be -1 if the request was cancelled or failed.
    * For wu_close_cb, -1 means that the handle was closed due to an error.
    * Error details can be obtained by calling wu_last_error().
    *
    * In the case of wu_read_cb the wu_buf returned should be freed by the
    * user.
    */
    typedef wu_buf (*wu_alloc_cb)(wu_handle_t* handle, size_t suggested_size);
    typedef void (*wu_read_cb)(wu_handle_t *handle, int nread, wu_buf buf);
    typedef void (*wu_write_cb)(wu_req_t* req, int status);
    typedef void (*wu_connect_cb)(wu_req_t* req, int status);
    typedef void (*wu_shutdown_cb)(wu_req_t* req, int status);
    typedef void (*wu_accept_cb)(wu_handle_t* handle);
    typedef void (*wu_close_cb)(wu_handle_t* handle, int status);
    typedef void (*wu_timer_cb)(wu_req_t* req, int64_t skew, int status);
    /* TODO: do loop_cb and async_cb really need a status argument? */
    typedef void (*wu_loop_cb)(wu_handle_t* handle, int status);
    typedef void (*wu_async_cb)(wu_handle_t* handle, int stats);


    /* Expand this list if necessary. */
    typedef enum {
    WU_UNKNOWN = -1,
    WU_OK = 0,
    WU_EOF,
    WU_EACCESS,
    WU_EAGAIN,
    WU_EADDRINUSE,
    WU_EADDRNOTAVAIL,
    WU_EAFNOSUPPORT,
    WU_EALREADY,
    WU_EBADF,
    WU_EBUSY,
    WU_ECONNABORTED,
    WU_ECONNREFUSED,
    WU_ECONNRESET,
    WU_EDESTADDRREQ,
    WU_EFAULT,
    WU_EHOSTUNREACH,
    WU_EINTR,
    WU_EINVAL,
    WU_EISCONN,
    WU_EMFILE,
    WU_ENETDOWN,
    WU_ENETUNREACH,
    WU_ENFILE,
    WU_ENOBUFS,
    WU_ENOMEM,
    WU_ENONET,
    WU_ENOPROTOOPT,
    WU_ENOTCONN,
    WU_ENOTSOCK,
    WU_ENOTSUP,
    WU_EPROTO,
    WU_EPROTONOSUPPORT,
    WU_EPROTOTYPE,
    WU_ETIMEDOUT
    } wu_err_code;

    typedef enum {
    WU_UNKNOWN_HANDLE = 0,
    WU_TCP,
    WU_NAMED_PIPE,
    WU_TTY,
    WU_FILE,
    WU_PREPARE,
    WU_CHECK,
    WU_IDLE,
    WU_ASYNC
    } wu_handle_type;

    typedef enum {
    WU_UNKNOWN_REQ = 0,
    WU_CONNECT,
    WU_ACCEPT,
    WU_READ,
    WU_WRITE,
    WU_SHUTDOWN,
    WU_TIMEOUT,
    WU_WAKEUP
    } wu_req_type;


    struct wu_err_s {
    /* read-only */
    wu_err_code code;
    /* private */
    int sys_errno_;
    };


    struct wu_req_s {
    /* read-only */
    wu_req_type type;
    /* public */
    wu_handle_t* handle;
    void* cb;
    void* data;
    /* private */
    wu_req_private_fields
    };


    struct wu_handle_s {
    /* read-only */
    wu_handle_type type;
    /* public */
    wu_close_cb close_cb;
    void* data;
    /* number of bytes queued for writing */
    size_t write_queue_size;
    /* private */
    wu_handle_private_fields
    };


    /* Most functions return boolean: 0 for success and -1 for failure.
    * On error the user should then call wu_last_error() to determine
    * the error code.
    */
    wu_err_t wu_last_error();
    char* wu_strerror(wu_err_t err);


    void wu_init(wu_alloc_cb alloc);
    int wu_run();

    /* Manually modify the event loop's reference count. Useful if the user wants
    * to have a handle or timeout that doesn't keep the loop alive.
    */
    void wu_ref();
    void wu_unref();

    void wu_update_time();
    int64_t wu_now();

    void wu_req_init(wu_req_t* req, wu_handle_t* handle, void* cb);

    /*
    * TODO:
    * - wu_(pipe|pipe_tty)_handle_init
    * - wu_bind_pipe(char* name)
    * - wu_continuous_read(wu_handle_t* handle, wu_continuous_read_cb* cb)
    * - A way to list cancelled wu_reqs after before/on wu_close_cb
    */

    /* TCP socket methods.
    * Handle and callback bust be set by calling wu_req_init.
    */
    int wu_tcp_init(wu_handle_t* handle, wu_close_cb close_cb, void* data);
    int wu_bind(wu_handle_t* handle, struct sockaddr* addr);

    int wu_connect(wu_req_t* req, struct sockaddr* addr);
    int wu_shutdown(wu_req_t* req);

    /* TCP server methods. */
    int wu_listen(wu_handle_t* handle, int backlog, wu_accept_cb cb);

    /* Call this after accept_cb. client does not need to be initialized. */
    int wu_accept(wu_handle_t* server, wu_handle_t* client,
    wu_close_cb close_cb, void* data);


    /* Read data from an incoming stream. The callback will be made several
    * several times until there is no more data to read or wu_read_stop is
    * called. When we've reached EOF nread will be set to -1 and the error is
    * set to WU_EOF. When nread == -1 the buf parameter might not point to a
    * valid buffer; in that case buf.len and buf.base are both set to 0.
    * Note that nread might also be 0, which does *not* indicate an error or
    * eof; it happens when libwu requested a buffer through the alloc callback
    * but then decided that it didn't need that buffer.
    */
    int wu_read_start(wu_handle_t* handle, wu_read_cb cb);
    int wu_read_stop(wu_handle_t* handle);

    int wu_write(wu_req_t* req, wu_buf bufs[], int bufcnt);

    /* Timer methods */
    int wu_timeout(wu_req_t* req, int64_t timeout);

    /* libev wrapper. Every active prepare handle gets its callback called
    * exactly once per loop iteration, just before the system blocks to wait
    * for completed i/o.
    */
    int wu_prepare_init(wu_handle_t* handle, wu_close_cb close_cb, void* data);
    int wu_prepare_start(wu_handle_t* handle, wu_loop_cb cb);
    int wu_prepare_stop(wu_handle_t* handle);

    /* libev wrapper. Every active check handle gets its callback called exactly
    * once per loop iteration, just after the system returns from blocking.
    */
    int wu_check_init(wu_handle_t* handle, wu_close_cb close_cb, void* data);
    int wu_check_start(wu_handle_t* handle, wu_loop_cb cb);
    int wu_check_stop(wu_handle_t* handle);

    /* libev wrapper. Every active idle handle gets its callback called repeatedly until it is
    * stopped. This happens after all other types of callbacks are processed.
    * When there are multiple "idle" handles active, their callbacks are called
    * in turn.
    */
    int wu_idle_init(wu_handle_t* handle, wu_close_cb close_cb, void* data);
    int wu_idle_start(wu_handle_t* handle, wu_loop_cb cb);
    int wu_idle_stop(wu_handle_t* handle);

    /* libev wrapper. wu_async_send wakes up the event loop and calls the async
    * handle's callback There is no guarantee that every wu_async_send call
    * leads to exactly one invocation of the callback; The only guarantee is
    * that the callback function is called at least once after the call to
    * async_send. Unlike everything else, wu_async_send can be called from
    * another thread.
    *
    * QUESTION(ryan) Can WU_ASYNC just use wu_loop_cb? Same signature on my
    * side.
    */
    int wu_async_init(wu_handle_t* handle, wu_async_cb async_cb,
    wu_close_cb close_cb, void* data);
    int wu_async_send(wu_handle_t* handle);

    /* Request handle to be closed. close_cb will be called
    * asynchronously after this call.
    */
    int wu_close(wu_handle_t* handle);


    /* Utility */
    struct sockaddr_in wu_ip4_addr(char* ip, int port);

    #endif /* WU_H */