/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2014 Couchbase, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBCOUCHBASE_COUCHBASE_H #error "include libcouchbase/couchbase.h first" #endif #ifndef LCB_IOPS_H #define LCB_IOPS_H /** * @file * @brief Public I/O integration interface * @details * * This file provides the public I/O interface for integrating with external * event loops. */ /** * @ingroup lcbio lcb-public-api * @defgroup lcb-io-plugin-api Network I/O * @details * * I/O Integration comes in two flavors: * * @par (E)vent/Poll Based Integration * This system is based upon the interfaces exposed by the `poll(2)` and * `select(2)` calls found in POSIX-based systems and are wrapped by systems * such as _libevent_ and _libev_. At their core is the notion that a socket * may be polled for readiness (either readiness for reading or readiness * for writing). When a socket is deemed ready, a callback is invoked indicating * which events took place. * * * @par (C)ompletion/Operation/Buffer Based Integration * This system is based upon the interfaces exposed in the Win32 API where * I/O is done in terms of operations which are awaiting _completion_. As such * buffers are passed into the core, and the application is notified when the * operation on those buffers (either read into a buffer, or write from a buffer) * has been completed. * * * @addtogroup lcb-io-plugin-api * @{ */ #ifdef __cplusplus extern "C" { #endif /** @brief Type representing the native socket type of the operating system */ #ifdef _WIN32 typedef SOCKET lcb_socket_t; #else typedef int lcb_socket_t; #endif struct sockaddr; #ifndef _WIN32 /** Defined if the lcb_IOV structure conforms to `struct iovec` */ #define LCB_IOV_LAYOUT_UIO typedef struct lcb_iovec_st { void *iov_base; size_t iov_len; } lcb_IOV; #else /** Defined if the lcb_IOV structure conforms to `WSABUF` */ #define LCB_IOV_LAYOUT_WSABUF typedef struct lcb_iovec_st { ULONG iov_len; void *iov_base; } lcb_IOV; #endif #if defined(LIBCOUCHBASE_INTERNAL) && !defined(LCB_IOPS_V12_NO_DEPRECATE) #define LCB__IOPS_CONCAT2(X, Y) X ## Y #define LCB__IOPS_CONCAT(X, Y) LCB__IOPS_CONCAT2(X, Y) #define LCB_IOPS_DEPRECATED(X) void (*LCB__IOPS_CONCAT(lcb__iops__dummy, __LINE__))(void) #else #define LCB_IOPS_DEPRECATED(X) X #endif /** @brief structure describing a connected socket's endpoints */ struct lcb_nameinfo_st { struct { struct sockaddr *name; int *len; } local; struct { struct sockaddr *name; int *len; } remote; }; /** * @struct lcb_IOV * @brief structure indicating a buffer and its size * * @details * This is compatible with a `struct iovec` on Unix and a `WSABUF` structure * on Windows. It has an `iov_base` field which is the base pointer and an * `iov_len` field which is the length of the buffer. */ typedef struct lcb_io_opt_st* lcb_io_opt_t; /** * @brief Callback invoked for all poll-like events * * @param sock the socket associated with the event * @param events the events which activated this callback. This is set of bits * comprising of LCB_READ_EVENT, LCB_WRITE_EVENT, and LCB_ERROR_EVENT * @param uarg a user-defined pointer passed to the * lcb_ioE_event_watch_fn routine. */ typedef void (*lcb_ioE_callback) (lcb_socket_t sock, short events, void *uarg); /**@name Timer Callbacks *@{*/ /** * @brief Create a new timer object. * * @param iops the io structure * @return an opaque timer handle. The timer shall remain inactive and shall * be destroyed via the lcb_io_timer_destroy_fn routine. */ typedef void *(*lcb_io_timer_create_fn) (lcb_io_opt_t iops); /** * @brief Destroy a timer handler * * Destroy a timer previously created with lcb_io_timer_create_fn * @param iops the io structure * @param timer the opaque handle * The timer must have already been cancelled via lcb_io_timer_cancel_fn */ typedef void (*lcb_io_timer_destroy_fn) (lcb_io_opt_t iops, void *timer); /** * @brief Cancel a pending timer callback * * Cancel and unregister a pending timer. If the timer has already * fired, this does nothing. If the timer has not yet fired, the callback * shall not be delivered. * * @param iops the I/O structure * @param timer the timer to cancel. */ typedef void (*lcb_io_timer_cancel_fn) (lcb_io_opt_t iops, void *timer); /** * @brief Schedule a callback to be invoked within a given interval. * * Schedule a timer to be fired within usec microseconds from now * @param iops the I/O structure * @param timer a timer previously created with timer_create * @param usecs the timer interval * @param uarg the user-defined pointer to be passed in the callback * @param callback the callback to invoke */ typedef int (*lcb_io_timer_schedule_fn) (lcb_io_opt_t iops, void *timer, lcb_U32 usecs, void *uarg, lcb_ioE_callback callback); /**@}*/ /**@name Event Handle Callbacks * @{*/ /** * @brief Create a new event handle. * * An event object may be used to monitor a socket for given I/O readiness events * @param iops the I/O structure. * @return a new event handle. * The handle may then be associated with a * socket and watched (via lcb_ioE_event_watch_fn) for I/O readiness. */ typedef void *(*lcb_ioE_event_create_fn) (lcb_io_opt_t iops); /** * @brief Destroy an event handle * * Destroy an event object. The object must not be active. * @param iops the I/O structure * @param event the event to free */ typedef void (*lcb_ioE_event_destroy_fn) (lcb_io_opt_t iops, void *event); /** * @deprecated lcb_ioE_event_watch_fn() should be used with `0` for events * @brief Cancel pending callbacks and unwatch a handle. * * @param iops the I/O structure * @param sock the socket associated with the event * @param event the opaque event object * * This function may be called multiple times and shall not fail even if the * event is already inactive. */ typedef void (*lcb_ioE_event_cancel_fn) (lcb_io_opt_t iops, lcb_socket_t sock, void *event); /** Data is available for reading */ #define LCB_READ_EVENT 0x02 /** Data can be written */ #define LCB_WRITE_EVENT 0x04 /** Exceptional condition ocurred on socket */ #define LCB_ERROR_EVENT 0x08 #define LCB_RW_EVENT (LCB_READ_EVENT|LCB_WRITE_EVENT) /** * Associate an event with a socket, requesting notification when one of * the events specified in 'flags' becomes available on the socket. * * @param iops the IO context * @param socket the socket to watch * @param event the event to associate with the socket. If this parameter is * @param evflags a bitflag of events to watch. This is one of LCB_READ_EVENT, * LCB_WRITE_EVENT, or LCB_RW_EVENT. * If this value is `0` then existing events shall be cancelled on the * socket. * * Note that the callback may _also_ receive LCB_ERROR_EVENT but this cannot * be requested as an event to watch for. * * @param uarg a user defined pointer to be passed to the callback * @param callback the callback to invoke when one of the events becomes * ready. * * @attention * It shall be legal to call this routine multiple times without having to call * the lcb_ioE_event_cancel_fn(). The cancel function should in fact be implemented * via passing a `0` to the `evflags` parameter, effectively clearing the * event. */ typedef int (*lcb_ioE_event_watch_fn) (lcb_io_opt_t iops, lcb_socket_t socket, void *event, short evflags, void *uarg, lcb_ioE_callback callback); /**@}*/ /**@name BSD-API I/O Routines * @{*/ /** * @brief Receive data into a single buffer * @see `recv(2)` socket API call. */ typedef lcb_SSIZE (*lcb_ioE_recv_fn) (lcb_io_opt_t iops, lcb_socket_t sock, void *target_buf, lcb_SIZE buflen, int _unused_flags); /** @brief Send data from a single buffer. * @see `send(2)` on POSIX */ typedef lcb_SSIZE (*lcb_ioE_send_fn) (lcb_io_opt_t iops, lcb_socket_t sock, const void *srcbuf, lcb_SIZE buflen, int _ignored); /**@brief Read data into a series of buffers. * @see the `recvmsg(2)` function on POSIX */ typedef lcb_SSIZE (*lcb_ioE_recvv_fn) (lcb_io_opt_t iops, lcb_socket_t sock, lcb_IOV *iov, lcb_SIZE niov); /**@brief Write data from multiple buffers. * @see the `sendmsg(2)` function on POSIX */ typedef lcb_SSIZE (*lcb_ioE_sendv_fn) (lcb_io_opt_t iops, lcb_socket_t sock, lcb_IOV *iov, lcb_SIZE niov); /**@brief Create a new socket. * @see `socket(2)` on POSIX */ typedef lcb_socket_t (*lcb_ioE_socket_fn) (lcb_io_opt_t iops, int domain, int type, int protocol); /**@brief Connect a created socket * @see `connect(2)` on POSIX */ typedef int (*lcb_ioE_connect_fn) (lcb_io_opt_t iops, lcb_socket_t sock, const struct sockaddr *dst, unsigned int addrlen); /** @private */ typedef int (*lcb_ioE_bind_fn) (lcb_io_opt_t iops, lcb_socket_t sock, const struct sockaddr *srcaddr, unsigned int addrlen); /** @private */ typedef int (*lcb_ioE_listen_fn) (lcb_io_opt_t iops, lcb_socket_t bound_sock, unsigned int queuelen); /** @private */ typedef lcb_socket_t (*lcb_ioE_accept_fn) (lcb_io_opt_t iops, lcb_socket_t lsnsock); /** @brief Close a socket * @see `close(2)` and `shutdown(2)` */ typedef void (*lcb_ioE_close_fn) (lcb_io_opt_t iops, lcb_socket_t sock); /** * While checking the socket, treat pending data as an _erorr_. * This flag will be _missing_ if the socket participates in a protocol * where unsolicited data is possible. * * Currently Couchbase does not provide such a protocol (at least not one where * sockets are placed in a pool), but it may in the future. * * This may be passed as a `flags` option to lcb_ioE_chkclosed_fn */ #define LCB_IO_SOCKCHECK_PEND_IS_ERROR 1 #define LCB_IO_SOCKCHECK_STATUS_CLOSED 1 #define LCB_IO_SOCKCHECK_STATUS_OK 0 #define LCB_IO_SOCKCHECK_STATUS_UNKNOWN -1 /**@brief Check if a socket has been closed or not. This is used to check * a socket's state after a period of inactivity. * * * @param iops The iops * @param sock The socket to check * @param flags A bit set of options. * @return A value greater than 0 if the socket _is_ closed, 0 if the socket * has not been closed, or a negative number, if the status could not be * determined within the given constraints (for example, if `flags` did not * specify `LCB_IO_SOCKCHECK_PEND_IS_ERROR`, and the implementation does not * have a way to check status otherwise. * * @since 2.4.4 */ typedef int (*lcb_ioE_chkclosed_fn) (lcb_io_opt_t iops, lcb_socket_t sock, int flags); /** For use with `io{E,C}_cntl_fn`, indicates the setting should be retrieved */ #define LCB_IO_CNTL_GET 0 /** For use with lcb_io{E,C}_cntl_fn`, indicates the setting should be modified */ #define LCB_IO_CNTL_SET 1 /** Disable Nagle's algorithm (use an int) */ #define LCB_IO_CNTL_TCP_NODELAY 1 /** Enable/Disable TCP Keepalive */ #define LCB_IO_CNTL_TCP_KEEPALIVE 2 /** * @brief Execute a specificied operation on a socket. * @param iops The iops * @param sock The socket * @param mode The mode, can be @ref LCB_IO_CNTL_GET or @ref LCB_IO_CNTL_SET * @param option The option to access * @param[in,out] arg the argument for the option * @return zero on success, nonzero on failure. */ typedef int (*lcb_ioE_cntl_fn) (lcb_io_opt_t iops, lcb_socket_t sock, int mode, int option, void *arg); /**@}*/ struct ringbuffer_st; struct lcb_connection_st; struct lcbio_SOCKET; /** @deprecated Ringbuffers are no longer used this way by the library for I/O */ struct lcb_buf_info { char *root; lcb_SIZE size; struct ringbuffer_st *ringbuffer; struct lcb_iovec_st iov[2]; }; /** * @brief Socket handle for completion-based I/O * * The sockdata structure is analoguous to an `lcb_socket_t` returned by * the E-model I/O. */ typedef struct lcb_sockdata_st { lcb_socket_t socket; /**< System socket, for informational purposes */ lcb_io_opt_t parent; /**< Parent I/O context */ struct lcbio_SOCKET *lcbconn; /**< Internal socket equivalent */ int closed; /**< @deprecated No longer used by the library */ int is_reading; /**< Internally used by lcbio */ struct lcb_buf_info read_buffer; /**< @deprecated No longer used by the library */ } lcb_sockdata_t; /** @deprecated */ typedef struct lcb_io_writebuf_st { struct lcb_io_opt_st *parent; struct lcb_buf_info buffer; } lcb_io_writebuf_t; /**@name Completion Routines * @{*/ /** * @brief Create a completion socket handle * * Create an opaque socket handle * @param iops the IO context * @param domain socket address family, e.g. AF_INET * @param type the transport type, e.g. SOCK_STREAM * @param protocol the IP protocol, e.g. IPPROTO_TCP * @return a socket pointer or NULL on failure. */ typedef lcb_sockdata_t* (*lcb_ioC_socket_fn) (lcb_io_opt_t iops, int domain, int type, int protocol); /** * @brief Callback to be invoked upon a connection result. * Callback invoked for a connection result. * @param socket the socket which is being connected * @param status the status. 0 for success, nonzero on failure */ typedef void (*lcb_io_connect_cb)(lcb_sockdata_t *socket, int status); /** * @brief Request a connection for a socket * @param iops the IO context * @param sd the socket pointer * @param dst the address to connect to * @param naddr the size of the address len, e.g. sizeof(struct sockaddr_in) * @param callback the callback to invoke when the connection status is determined * @return 0 on success, nonzero if a connection could not be scheduled. */ typedef int (*lcb_ioC_connect_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd, const struct sockaddr *dst, unsigned int naddr, lcb_io_connect_cb callback); /** * @brief Callback invoked when a new client connection has been established * @param sd_server the server listen socket * @param sd_client the new client socket * @param status if there was an error accepting (in this case, sd_client is NULL */ typedef void (lcb_ioC_serve_callback) (lcb_sockdata_t *sd_server, lcb_sockdata_t *sd_client, int status); /** * Specify that the socket start accepting connections. This should be called * on a newly created non-connected socket * @param iops the I/O context * @param server_socket the socket used to listen with * @param sockaddr the local address for listening * @param callback the callback to invoke for each new connection */ typedef int (*lcb_ioC_serve_fn) (lcb_io_opt_t iops, lcb_sockdata_t *server_socket, const struct sockaddr *listen_addr, lcb_ioC_serve_callback callback); /** * @brief Request address information on a connected socket * @param iops the I/O context * @param sock the socket from which to retrieve information * @param ni a nameinfo structure to populate with the relevant details */ typedef int (*lcb_ioC_nameinfo_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sock, struct lcb_nameinfo_st *ni); /**@deprecated*/ typedef void (*lcb_ioC_read_callback)(lcb_sockdata_t *sd, lcb_SSIZE nread); #define lcb_io_read_cb lcb_ioC_read_callback /**@deprecated See lcb_ioC_read2_fn(). Wrapped if not implemented*/ typedef int (*lcb_ioC_read_fn)(lcb_io_opt_t,lcb_sockdata_t*,lcb_ioC_read_callback); /**@deprecated See lcb_ioC_write2_fn(). Wrapped if not implemented*/ typedef lcb_io_writebuf_t* (*lcb_ioC_wballoc_fn)(lcb_io_opt_t,lcb_sockdata_t *); /**@deprecated See lcb_ioC_write2_fn(). Wrapped if not implemented */ typedef void (*lcb_ioC_wbfree_fn)(lcb_io_opt_t,lcb_sockdata_t*,lcb_io_writebuf_t*); /**@deprecated See lcb_ioC_write2_fn(). This will be wrapped if not implemented */ typedef void (*lcb_ioC_write_callback)(lcb_sockdata_t*,lcb_io_writebuf_t*,int); #define lcb_io_write_cb lcb_ioC_write_callback /**@deprecated*/ typedef int (*lcb_ioC_write_fn) (lcb_io_opt_t,lcb_sockdata_t*,lcb_io_writebuf_t*,lcb_ioC_write_callback); /** * @brief Callback received when a buffer has been flushed * @param sd the socket * @param status nonzero on error * @param arg the opaque handle passed in the write2 call */ typedef void (*lcb_ioC_write2_callback) (lcb_sockdata_t *sd, int status, void *arg); /** * @brief Schedule a flush of a series of buffers to the network * * @param iops the I/O context * @param sd the socket on which to send * @param iov an array of IOV structures. * The buffers pointed to by the IOVs themselves (i.e. `iov->iov_len`) * **must** not be freed or modified until the callback has been invoked. * The storage for the IOVs themselves (i.e. the array passed in `iov`) * is copied internally to the implementation. * * @param niov the number of IOV structures within the array * @param uarg an opaque pointer to be passed in the callback * @param callback the callback to invoke. This will be called when the buffers * passed have either been completely flushed (and are no longer required) * or when an error has taken place. */ typedef int (*lcb_ioC_write2_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd, lcb_IOV *iov, lcb_SIZE niov, void *uarg, lcb_ioC_write2_callback callback); /** * @brief Callback invoked when a read has been completed * @param sd the socket * @param nread number of bytes read, or -1 on error * @param arg user provided argument for callback. */ typedef void (*lcb_ioC_read2_callback) (lcb_sockdata_t *sd, lcb_SSIZE nread, void *arg); /** * @brief Schedule a read from the network * @param iops the I/O context * @param sd the socket on which to read * @param iov an array of IOV structures * @param niov the number of IOV structures within the array * @param uarg a pointer passed to the callback * @param callback the callback to invoke * @return 0 on success, nonzero on error * * The IOV array itself shall copied (if needed) into the I/O implementation * and thus does not need to be kept in memory after the function has been * called. Note that the underlying buffers _do_ need to remain valid until * the callback is received. */ typedef int (*lcb_ioC_read2_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd, lcb_IOV *iov, lcb_SIZE niov, void *uarg, lcb_ioC_read2_callback callback); /** * @brief Asynchronously shutdown the socket. * * Request an asynchronous close for the specified socket. This merely releases * control from the library over to the plugin for the specified socket and * does _not_ actually imply that the resources have been closed. * * Notable, callbacks for read and write operations will _still_ be invoked * in order to maintain proper resource deallocation. However the socket's * closed field will be set to true. * * @param iops the I/O context * @param sd the socket structure */ typedef unsigned int (*lcb_ioC_close_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd); /** * This is the completion variant of @ref lcb_ioE_chkclosed_fn. See that * function for details * * @param iops * @param sd * @param flags * @return */ typedef int (*lcb_ioC_chkclosed_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd, int flags); /** * @see lcb_ioE_cntl_fn. * * @param iops * @param sd * @param mode * @param option * @param arg * @return */ typedef int (*lcb_ioC_cntl_fn) (lcb_io_opt_t iops, lcb_sockdata_t *sd, int mode, int option, void *arg); /**@}*/ /** * @brief Start the event loop * @param iops The I/O context * * This should start polling for socket events on all registered watchers * and scheduled events. This function should return either when there are * no more timers or events pending, or when lcb_io_stop_fn() has been invoked. */ typedef void (*lcb_io_start_fn)(lcb_io_opt_t iops); /** * @brief Run a single iteration of the event loop without blocking. This * is intended to be an optimization to allow scheduled I/O operations to * complete without blocking the main thread */ typedef void (*lcb_io_tick_fn)(lcb_io_opt_t iops); /** * @brief Pause the event loop * @param iops The I/O Context * * This function shall suspend the event loop, causing a current invocation * to lcb_io_start_fn() to return as soon as possible */ typedef void (*lcb_io_stop_fn)(lcb_io_opt_t iops); LCB_DEPRECATED(typedef void (*lcb_io_error_cb)(lcb_sockdata_t *socket)); #define LCB_IOPS_BASE_FIELDS \ void *cookie; \ int error; \ int need_cleanup; struct lcb_iops_evented_st { LCB_IOPS_BASE_FIELDS LCB_IOPS_DEPRECATED(lcb_ioE_socket_fn socket); LCB_IOPS_DEPRECATED(lcb_ioE_connect_fn connect); LCB_IOPS_DEPRECATED(lcb_ioE_recv_fn recv); LCB_IOPS_DEPRECATED(lcb_ioE_send_fn send); LCB_IOPS_DEPRECATED(lcb_ioE_recvv_fn recvv); LCB_IOPS_DEPRECATED(lcb_ioE_sendv_fn sendv); LCB_IOPS_DEPRECATED(lcb_ioE_close_fn close); LCB_IOPS_DEPRECATED(lcb_io_timer_create_fn create_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_destroy_fn destroy_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_cancel_fn delete_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_schedule_fn update_timer); LCB_IOPS_DEPRECATED(lcb_ioE_event_create_fn create_event); LCB_IOPS_DEPRECATED(lcb_ioE_event_destroy_fn destroy_event); LCB_IOPS_DEPRECATED(lcb_ioE_event_watch_fn update_event); LCB_IOPS_DEPRECATED(lcb_ioE_event_cancel_fn delete_event); LCB_IOPS_DEPRECATED(lcb_io_stop_fn stop_event_loop); LCB_IOPS_DEPRECATED(lcb_io_start_fn run_event_loop); }; struct lcb_iops_completion_st { LCB_IOPS_BASE_FIELDS LCB_IOPS_DEPRECATED(lcb_ioC_socket_fn create_socket); LCB_IOPS_DEPRECATED(lcb_ioC_connect_fn start_connect); LCB_IOPS_DEPRECATED(lcb_ioC_wballoc_fn create_writebuf); LCB_IOPS_DEPRECATED(lcb_ioC_wbfree_fn release_writebuf); LCB_IOPS_DEPRECATED(lcb_ioC_write_fn start_write); LCB_IOPS_DEPRECATED(lcb_ioC_read_fn start_read); LCB_IOPS_DEPRECATED(lcb_ioC_close_fn close_socket); LCB_IOPS_DEPRECATED(lcb_io_timer_create_fn create_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_destroy_fn destroy_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_cancel_fn delete_timer); LCB_IOPS_DEPRECATED(lcb_io_timer_schedule_fn update_timer); LCB_IOPS_DEPRECATED(lcb_ioC_nameinfo_fn get_nameinfo); void (*pad1)(void); void (*pad2)(void); LCB_IOPS_DEPRECATED(void (*send_error)(struct lcb_io_opt_st*, lcb_sockdata_t*,void(*)(lcb_sockdata_t*))); LCB_IOPS_DEPRECATED(lcb_io_stop_fn stop_event_loop); LCB_IOPS_DEPRECATED(lcb_io_start_fn run_event_loop); }; /** @brief Common functions for starting and stopping timers */ typedef struct lcb_timerprocs_st { lcb_io_timer_create_fn create; lcb_io_timer_destroy_fn destroy; lcb_io_timer_cancel_fn cancel; lcb_io_timer_schedule_fn schedule; } lcb_timer_procs; /** @brief Common functions for starting and stopping the event loop */ typedef struct lcb_loopprocs_st { lcb_io_start_fn start; lcb_io_stop_fn stop; lcb_io_tick_fn tick; } lcb_loop_procs; /** @brief Functions wrapping the Berkeley Socket API */ typedef struct lcb_bsdprocs_st { lcb_ioE_socket_fn socket0; lcb_ioE_connect_fn connect0; lcb_ioE_recv_fn recv; lcb_ioE_recvv_fn recvv; lcb_ioE_send_fn send; lcb_ioE_sendv_fn sendv; lcb_ioE_close_fn close; lcb_ioE_bind_fn bind; lcb_ioE_listen_fn listen; lcb_ioE_accept_fn accept; lcb_ioE_chkclosed_fn is_closed; lcb_ioE_cntl_fn cntl; } lcb_bsd_procs; /** @brief Functions handling socket watcher events */ typedef struct lcb_evprocs_st { lcb_ioE_event_create_fn create; lcb_ioE_event_destroy_fn destroy; lcb_ioE_event_cancel_fn cancel; lcb_ioE_event_watch_fn watch; } lcb_ev_procs; /** @brief Functions for completion-based I/O */ typedef struct { lcb_ioC_socket_fn socket; lcb_ioC_close_fn close; lcb_ioC_read_fn read; lcb_ioC_connect_fn connect; lcb_ioC_wballoc_fn wballoc; lcb_ioC_wbfree_fn wbfree; lcb_ioC_write_fn write; lcb_ioC_write2_fn write2; lcb_ioC_read2_fn read2; lcb_ioC_serve_fn serve; lcb_ioC_nameinfo_fn nameinfo; lcb_ioC_chkclosed_fn is_closed; lcb_ioC_cntl_fn cntl; } lcb_completion_procs; /** * Enumeration defining the I/O model */ typedef enum { LCB_IOMODEL_EVENT, /**< Event/Poll style */ LCB_IOMODEL_COMPLETION /**< IOCP/Completion style */ } lcb_iomodel_t; /** * @param version the ABI/API version for the proc structures. Note that * ABI is forward compatible for all proc structures, meaning that newer * versions will always extend new fields and never replace existing ones. * However in order to avoid a situation where a newer version of a plugin * is loaded against an older version of the library (in which case the plugin * will assume the proc table size is actually bigger than it is) the version * serves as an indicator for this. The version actually passed is defined * in `LCB_IOPROCS_VERSION` * * @param loop_procs a table to be set to basic loop control routines * @param timer_procs a table to be set to the timer routines * @param bsd_procs a table to be set to BSD socket API routines * @param ev_procs a table to be set to event watcher routines * @param completion_procs a table to be set to completion routines * @param iomodel the I/O model to be used. If this is `LCB_IOMODEL_COMPLETION` * then the contents of `bsd_procs` will be ignored and `completion_procs` must * be populated. If the mode is `LCB_IOMODEL_EVENT` then the `bsd_procs` must be * populated and `completion_procs` is ignored. * * Important to note that internally the `ev`, `bsd`, and `completion` field are * defined as a union, thus * @code{.c} * union { * struct { * lcb_bsd_procs; * lcb_ev_procs; * } event; * struct lcb_completion_procs completion; * } * @endcode * thus setting both fields will actually clobber. * * @attention * Note that the library takes ownership of the passed tables and it should * not be controlled or accessed by the plugin. * * @attention * This function may not have any side effects as it may be called * multiple times. * * As opposed to the v0 and v1 IOPS structures that require a table to be * populated and returned, the v2 IOPS works differently. Specifically, the * IOPS population happens at multiple stages: * * 1. The base structure is returned, i.e. `lcb_create_NAME_iops` where _NAME_ * is the name of the plugin * * 2. Once the structure is returned, LCB shall invoke the `v.v2.get_procs()` * function. The callback is responsible for populating the relevant fields. * * Note that the old `v0` and `v1` fields are now proxied via this mechanism. * It _is_ possible to still monkey-patch the IO routines, but ensure the * monkey patching takes place _before_ the instance is created (as the * instance will initialize its own IO Table); thus, e.g. * @code{.c} * static void monkey_proc_fn(...) { * // * } * * static void monkey_patch_io(lcb_io_opt_t io) { * io->v.v0.get_procs = monkey_proc_fn; * } * * int main(void) { * lcb_create_st options; * lcb_t instance; * lcb_io_opt_t io; * lcb_create_iops(&io, NULL); * monkey_patch_io(io); * options.v.v0.io = io; * lcb_create(&instance, &options); * // ... * } * @endcode * * Typically the `get_procs` function will only be called once, and this will * happen from within lcb_create(). Thus in order to monkey patch you must * ensure that initially the `get_procs` function itself is first supplanted * and then return your customized I/O routines from your own `get_procs` (in * this example, `monkey_proc_fn()`) * */ typedef void (*lcb_io_procs_fn) (int version, lcb_loop_procs *loop_procs, lcb_timer_procs *timer_procs, lcb_bsd_procs *bsd_procs, lcb_ev_procs *ev_procs, lcb_completion_procs *completion_procs, lcb_iomodel_t *iomodel); struct lcbio_TABLE; struct lcb_iops2_st { LCB_IOPS_BASE_FIELDS lcb_io_procs_fn get_procs; struct lcbio_TABLE *iot; }; /* This is here to provide backwards compatibility with older (broken) clients * which attempt to 'subclass' the select plugin, or similar. In this case we * provide 17 callback fields (unused here) which the plugin implementation * may set, so that the older code can continue to function without upgrading * the client to a newer version. This should not be used except by internal * plugins; specifically the ABI layout of this field is subject to change * (for example, additional fields may be added or existing fields may be * renamed/removed) without notice. */ typedef void (*lcb__iops3fndummy)(void); struct lcb_iops3_st { LCB_IOPS_BASE_FIELDS lcb__iops3fndummy pads[17]; lcb_io_procs_fn get_procs; struct lcbio_TABLE *iot; }; /** * This number is bumped up each time a new field is added to any of the * function tables. This number is backwards compatible (i.e. version 3 contains * all the fields of version 2, and some additional ones) */ #define LCB_IOPROCS_VERSION 4 #define LCB_IOPS_BASEFLD(iops, fld) ((iops)->v.base).fld #define LCB_IOPS_ERRNO(iops) LCB_IOPS_BASEFLD(iops, error) struct lcb_io_opt_st { int version; void *dlhandle; void (*destructor)(struct lcb_io_opt_st *iops); union { struct { LCB_IOPS_BASE_FIELDS } base; /** These two names are deprecated internally */ struct lcb_iops_evented_st v0; struct lcb_iops_completion_st v1; struct lcb_iops2_st v2; struct lcb_iops3_st v3; } v; }; /** * @brief Signature for a loadable plugin's IOPS initializer * * @param version the plugin init API version. This will be 0 for this function * @param io a pointer to be set to the I/O table * @param cookie a user-defined argument passed to the I/O initializer * @return LCB_SUCCESS on success, an error on failure */ typedef lcb_error_t (*lcb_io_create_fn) (int version, lcb_io_opt_t *io, void *cookie); /** * @volatile * * This is an alternative to copying the 'bsdio-inl.c' file around. It is * designed specifically for the @ref lcb_io_procs_fn function and will do the * job of applying the current _runtime_ version of the default event-based I/O * implementation. * * e.g. * @code{.c} * static void getprocs_impl(int version, lcb_loop_procs *loop_procs, * lcb_timer_procs *timer_procs, lcb_bsd_procs *bsd_procs, * lcb_ev_procs *ev_procs, lcb_completion_procs *completion_procs, * lcb_iomodel_t *iomodel) { * * // do stuff normally * // .. * // install the default I/O handlers: * lcb_iops_wire_bsd_impl2(bsd_procs, version); * @endcode * * Use this function with care, and understand the implications between using * this API call and embedding the `bsdio-inl.c` source file. Specifically: * * - If your application is using an _older_ version of the library, this * implementation may contain bugs not present in the version you compiled * against (and an embedded version may be newer) * - If your application is using a _newer_ version, there may be some additional * I/O functions which you may wish to wrap or rather not implement at all, * but will be implemented if you call this function. */ LIBCOUCHBASE_API void lcb_iops_wire_bsd_impl2(lcb_bsd_procs *procs, int version); /****************************************************************************** ****************************************************************************** ** IO CREATION ** ****************************************************************************** ******************************************************************************/ /** * @brief Built-in I/O plugins * @committed */ typedef enum { LCB_IO_OPS_INVALID = 0x00, /**< @private */ LCB_IO_OPS_DEFAULT = 0x01, /**< @private */ /** Integrate with the libevent loop. See lcb_create_libevent_io_opts() */ LCB_IO_OPS_LIBEVENT = 0x02, LCB_IO_OPS_WINSOCK = 0x03, /**< @private */ LCB_IO_OPS_LIBEV = 0x04, LCB_IO_OPS_SELECT = 0x05, LCB_IO_OPS_WINIOCP = 0x06, LCB_IO_OPS_LIBUV = 0x07 } lcb_io_ops_type_t; /** @brief IO Creation for builtin plugins */ typedef struct { lcb_io_ops_type_t type; /**< The predefined type you want to create */ void *cookie; /**< Plugin-specific argument */ } lcb_IOCREATEOPTS_BUILTIN; #ifndef __LCB_DOXYGEN__ /* These are mostly internal structures which may be in use by older applications.*/ typedef struct { const char *sofile; const char *symbol; void *cookie; } lcb_IOCREATEOPTS_DSO; typedef struct { lcb_io_create_fn create; void *cookie; } lcb_IOCREATEOPS_FUNCTIONPOINTER; #endif /** @uncommited */ struct lcb_create_io_ops_st { int version; union { lcb_IOCREATEOPTS_BUILTIN v0; lcb_IOCREATEOPTS_DSO v1; lcb_IOCREATEOPS_FUNCTIONPOINTER v2; } v; }; /** * Create a new instance of one of the library-supplied io ops types. * * This function should only be used if you wish to override/customize the * default I/O plugin behavior; for example to select a specific implementation * (e.g. always for the _select_ plugin) and/or to integrate * a builtin plugin with your own application (e.g. pass an existing `event_base` * structure to the _libevent_ plugin). * * If you _do_ use this function, then you must call lcb_destroy_io_ops() on * the plugin handle once it is no longer required (and no instance is using * it). * * Whether a single `lcb_io_opt_t` may be used by multiple instances at once * is dependent on the specific implementation, but as a general rule it should * be assumed to be unsafe. * * @param[out] op The newly created io ops structure * @param options How to create the io ops structure * @return @ref LCB_SUCCESS on success * @uncommitted */ LIBCOUCHBASE_API lcb_error_t lcb_create_io_ops(lcb_io_opt_t *op, const struct lcb_create_io_ops_st *options); /** * Destroy the plugin handle created by lcb_create_io_ops() * @param op ops structure * @return LCB_SUCCESS on success * @uncommitted */ LIBCOUCHBASE_API lcb_error_t lcb_destroy_io_ops(lcb_io_opt_t op); #ifdef __cplusplus } #endif /**@}*/ #endif