Skip to content

Instantly share code, notes, and snippets.

@ry
Created May 12, 2011 02:05
Show Gist options
  • Save ry/967799 to your computer and use it in GitHub Desktop.
Save ry/967799 to your computer and use it in GitHub Desktop.
/* 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 */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment