summaryrefslogtreecommitdiff
path: root/thirdparty/wslay
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/wslay')
-rw-r--r--thirdparty/wslay/COPYING22
-rw-r--r--thirdparty/wslay/includes/config.h8
-rw-r--r--thirdparty/wslay/includes/wslay/wslay.h778
-rw-r--r--thirdparty/wslay/includes/wslay/wslayver.h31
-rw-r--r--thirdparty/wslay/msvcfix.diff17
-rw-r--r--thirdparty/wslay/wslay_event.c1027
-rw-r--r--thirdparty/wslay/wslay_event.h142
-rw-r--r--thirdparty/wslay/wslay_frame.c340
-rw-r--r--thirdparty/wslay/wslay_frame.h76
-rw-r--r--thirdparty/wslay/wslay_net.c36
-rw-r--r--thirdparty/wslay/wslay_net.h54
-rw-r--r--thirdparty/wslay/wslay_queue.c117
-rw-r--r--thirdparty/wslay/wslay_queue.h53
-rw-r--r--thirdparty/wslay/wslay_stack.c86
-rw-r--r--thirdparty/wslay/wslay_stack.h50
15 files changed, 2837 insertions, 0 deletions
diff --git a/thirdparty/wslay/COPYING b/thirdparty/wslay/COPYING
new file mode 100644
index 0000000000..6080330303
--- /dev/null
+++ b/thirdparty/wslay/COPYING
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2011, 2012, 2015 Tatsuhiro Tsujikawa
+
+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.
diff --git a/thirdparty/wslay/includes/config.h b/thirdparty/wslay/includes/config.h
new file mode 100644
index 0000000000..771ad12528
--- /dev/null
+++ b/thirdparty/wslay/includes/config.h
@@ -0,0 +1,8 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#ifdef BIG_ENDIAN_ENABLED
+#define WORDS_BIGENDIAN
+#endif
+
+#endif /* CONFIG_H */
diff --git a/thirdparty/wslay/includes/wslay/wslay.h b/thirdparty/wslay/includes/wslay/wslay.h
new file mode 100644
index 0000000000..9c751b05b7
--- /dev/null
+++ b/thirdparty/wslay/includes/wslay/wslay.h
@@ -0,0 +1,778 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_H
+#define WSLAY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+/* GODOT ADDITTION */
+#if defined(_MSC_VER)
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#endif
+/* GODOT END */
+
+/*
+ * wslay/wslayver.h is generated from wslay/wslayver.h.in by
+ * configure. The projects which do not use autotools can set
+ * WSLAY_VERSION macro from outside to avoid to generating wslayver.h
+ */
+#ifndef WSLAY_VERSION
+# include <wslay/wslayver.h>
+#endif /* WSLAY_VERSION */
+
+enum wslay_error {
+ WSLAY_ERR_WANT_READ = -100,
+ WSLAY_ERR_WANT_WRITE = -101,
+ WSLAY_ERR_PROTO = -200,
+ WSLAY_ERR_INVALID_ARGUMENT = -300,
+ WSLAY_ERR_INVALID_CALLBACK = -301,
+ WSLAY_ERR_NO_MORE_MSG = -302,
+ WSLAY_ERR_CALLBACK_FAILURE = -400,
+ WSLAY_ERR_WOULDBLOCK = -401,
+ WSLAY_ERR_NOMEM = -500
+};
+
+/*
+ * Status codes defined in RFC6455
+ */
+enum wslay_status_code {
+ WSLAY_CODE_NORMAL_CLOSURE = 1000,
+ WSLAY_CODE_GOING_AWAY = 1001,
+ WSLAY_CODE_PROTOCOL_ERROR = 1002,
+ WSLAY_CODE_UNSUPPORTED_DATA = 1003,
+ WSLAY_CODE_NO_STATUS_RCVD = 1005,
+ WSLAY_CODE_ABNORMAL_CLOSURE = 1006,
+ WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA = 1007,
+ WSLAY_CODE_POLICY_VIOLATION = 1008,
+ WSLAY_CODE_MESSAGE_TOO_BIG = 1009,
+ WSLAY_CODE_MANDATORY_EXT = 1010,
+ WSLAY_CODE_INTERNAL_SERVER_ERROR = 1011,
+ WSLAY_CODE_TLS_HANDSHAKE = 1015
+};
+
+enum wslay_io_flags {
+ /*
+ * There is more data to send.
+ */
+ WSLAY_MSG_MORE = 1
+};
+
+/*
+ * Callback function used by wslay_frame_send() function when it needs
+ * to send data. The implementation of this function must send at most
+ * len bytes of data in data. flags is the bitwise OR of zero or more
+ * of the following flag:
+ *
+ * WSLAY_MSG_MORE
+ * There is more data to send
+ *
+ * It provides some hints to tune performance and behaviour. user_data
+ * is one given in wslay_frame_context_init() function. The
+ * implementation of this function must return the number of bytes
+ * sent. If there is an error, return -1. The return value 0 is also
+ * treated an error by the library.
+ */
+typedef ssize_t (*wslay_frame_send_callback)(const uint8_t *data, size_t len,
+ int flags, void *user_data);
+/*
+ * Callback function used by wslay_frame_recv() function when it needs
+ * more data. The implementation of this function must fill at most
+ * len bytes of data into buf. The memory area of buf is allocated by
+ * library and not be freed by the application code. flags is always 0
+ * in this version. user_data is one given in
+ * wslay_frame_context_init() function. The implementation of this
+ * function must return the number of bytes filled. If there is an
+ * error, return -1. The return value 0 is also treated an error by
+ * the library.
+ */
+typedef ssize_t (*wslay_frame_recv_callback)(uint8_t *buf, size_t len,
+ int flags, void *user_data);
+/*
+ * Callback function used by wslay_frame_send() function when it needs
+ * new mask key. The implementation of this function must write
+ * exactly len bytes of mask key to buf. user_data is one given in
+ * wslay_frame_context_init() function. The implementation of this
+ * function return 0 on success. If there is an error, return -1.
+ */
+typedef int (*wslay_frame_genmask_callback)(uint8_t *buf, size_t len,
+ void *user_data);
+
+struct wslay_frame_callbacks {
+ wslay_frame_send_callback send_callback;
+ wslay_frame_recv_callback recv_callback;
+ wslay_frame_genmask_callback genmask_callback;
+};
+
+/*
+ * The opcode defined in RFC6455.
+ */
+enum wslay_opcode {
+ WSLAY_CONTINUATION_FRAME = 0x0u,
+ WSLAY_TEXT_FRAME = 0x1u,
+ WSLAY_BINARY_FRAME = 0x2u,
+ WSLAY_CONNECTION_CLOSE = 0x8u,
+ WSLAY_PING = 0x9u,
+ WSLAY_PONG = 0xau
+};
+
+/*
+ * Macro that returns 1 if opcode is control frame opcode, otherwise
+ * returns 0.
+ */
+#define wslay_is_ctrl_frame(opcode) ((opcode >> 3) & 1)
+
+/*
+ * Macros that represent and return reserved bits: RSV1, RSV2, RSV3.
+ * These macros assume that rsv is constructed by ((RSV1 << 2) |
+ * (RSV2 << 1) | RSV3)
+ */
+#define WSLAY_RSV_NONE ((uint8_t) 0)
+#define WSLAY_RSV1_BIT (((uint8_t) 1) << 2)
+#define WSLAY_RSV2_BIT (((uint8_t) 1) << 1)
+#define WSLAY_RSV3_BIT (((uint8_t) 1) << 0)
+
+#define wslay_get_rsv1(rsv) ((rsv >> 2) & 1)
+#define wslay_get_rsv2(rsv) ((rsv >> 1) & 1)
+#define wslay_get_rsv3(rsv) (rsv & 1)
+
+struct wslay_frame_iocb {
+ /* 1 for fragmented final frame, 0 for otherwise */
+ uint8_t fin;
+ /*
+ * reserved 3 bits. rsv = ((RSV1 << 2) | (RSV << 1) | RSV3).
+ * RFC6455 requires 0 unless extensions are negotiated.
+ */
+ uint8_t rsv;
+ /* 4 bit opcode */
+ uint8_t opcode;
+ /* payload length [0, 2**63-1] */
+ uint64_t payload_length;
+ /* 1 for masked frame, 0 for unmasked */
+ uint8_t mask;
+ /* part of payload data */
+ const uint8_t *data;
+ /* bytes of data defined above */
+ size_t data_length;
+};
+
+struct wslay_frame_context;
+typedef struct wslay_frame_context *wslay_frame_context_ptr;
+
+/*
+ * Initializes ctx using given callbacks and user_data. This function
+ * allocates memory for struct wslay_frame_context and stores the
+ * result to *ctx. The callback functions specified in callbacks are
+ * copied to ctx. user_data is stored in ctx and it will be passed to
+ * callback functions. When the user code finished using ctx, it must
+ * call wslay_frame_context_free to deallocate memory.
+ */
+int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
+ const struct wslay_frame_callbacks *callbacks,
+ void *user_data);
+
+/*
+ * Deallocates memory pointed by ctx.
+ */
+void wslay_frame_context_free(wslay_frame_context_ptr ctx);
+
+/*
+ * Send WebSocket frame specified in iocb. ctx must be initialized
+ * using wslay_frame_context_init() function. iocb->fin must be 1 if
+ * this is a fin frame, otherwise 0. iocb->rsv is reserved bits.
+ * iocb->opcode must be the opcode of this frame. iocb->mask must be
+ * 1 if this is masked frame, otherwise 0. iocb->payload_length is
+ * the payload_length of this frame. iocb->data must point to the
+ * payload data to be sent. iocb->data_length must be the length of
+ * the data. This function calls send_callback function if it needs
+ * to send bytes. This function calls gen_mask_callback function if
+ * it needs new mask key. This function returns the number of payload
+ * bytes sent. Please note that it does not include any number of
+ * header bytes. If it cannot send any single bytes of payload, it
+ * returns WSLAY_ERR_WANT_WRITE. If the library detects error in iocb,
+ * this function returns WSLAY_ERR_INVALID_ARGUMENT. If callback
+ * functions report a failure, this function returns
+ * WSLAY_ERR_INVALID_CALLBACK. This function does not always send all
+ * given data in iocb. If there are remaining data to be sent, adjust
+ * data and data_length in iocb accordingly and call this function
+ * again.
+ */
+ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb);
+
+/*
+ * Receives WebSocket frame and stores it in iocb. This function
+ * returns the number of payload bytes received. This does not
+ * include header bytes. In this case, iocb will be populated as
+ * follows: iocb->fin is 1 if received frame is fin frame, otherwise
+ * 0. iocb->rsv is reserved bits of received frame. iocb->opcode is
+ * opcode of received frame. iocb->mask is 1 if received frame is
+ * masked, otherwise 0. iocb->payload_length is the payload length of
+ * received frame. iocb->data is pointed to the buffer containing
+ * received payload data. This buffer is allocated by the library and
+ * must be read-only. iocb->data_length is the number of payload
+ * bytes recieved. This function calls recv_callback if it needs to
+ * receive additional bytes. If it cannot receive any single bytes of
+ * payload, it returns WSLAY_ERR_WANT_READ. If the library detects
+ * protocol violation in a received frame, this function returns
+ * WSLAY_ERR_PROTO. If callback functions report a failure, this
+ * function returns WSLAY_ERR_INVALID_CALLBACK. This function does
+ * not always receive whole frame in a single call. If there are
+ * remaining data to be received, call this function again. This
+ * function ensures frame alignment.
+ */
+ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb);
+
+struct wslay_event_context;
+/* Pointer to the event-based API context */
+typedef struct wslay_event_context *wslay_event_context_ptr;
+
+struct wslay_event_on_msg_recv_arg {
+ /* reserved bits: rsv = (RSV1 << 2) | (RSV2 << 1) | RSV3 */
+ uint8_t rsv;
+ /* opcode */
+ uint8_t opcode;
+ /* received message */
+ const uint8_t *msg;
+ /* message length */
+ size_t msg_length;
+ /*
+ * Status code iff opcode == WSLAY_CONNECTION_CLOSE. If no status
+ * code is included in the close control frame, it is set to 0.
+ */
+ uint16_t status_code;
+};
+
+/*
+ * Callback function invoked by wslay_event_recv() when a message is
+ * completely received.
+ */
+typedef void (*wslay_event_on_msg_recv_callback)
+(wslay_event_context_ptr ctx,
+ const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
+
+struct wslay_event_on_frame_recv_start_arg {
+ /* fin bit; 1 for final frame, or 0. */
+ uint8_t fin;
+ /* reserved bits: rsv = (RSV1 << 2) | (RSV2 << 1) | RSV3 */
+ uint8_t rsv;
+ /* opcode of the frame */
+ uint8_t opcode;
+ /* payload length of ths frame */
+ uint64_t payload_length;
+};
+
+/*
+ * Callback function invoked by wslay_event_recv() when a new frame
+ * starts to be received. This callback function is only invoked once
+ * for each frame.
+ */
+typedef void (*wslay_event_on_frame_recv_start_callback)
+(wslay_event_context_ptr ctx,
+ const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
+
+struct wslay_event_on_frame_recv_chunk_arg {
+ /* chunk of payload data */
+ const uint8_t *data;
+ /* length of data */
+ size_t data_length;
+};
+
+/*
+ * Callback function invoked by wslay_event_recv() when a chunk of
+ * frame payload is received.
+ */
+typedef void (*wslay_event_on_frame_recv_chunk_callback)
+(wslay_event_context_ptr ctx,
+ const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
+
+/*
+ * Callback function invoked by wslay_event_recv() when a frame is
+ * completely received.
+ */
+typedef void (*wslay_event_on_frame_recv_end_callback)
+(wslay_event_context_ptr ctx, void *user_data);
+
+/*
+ * Callback function invoked by wslay_event_recv() when it wants to
+ * receive more data from peer. The implementation of this callback
+ * function must read data at most len bytes from peer and store them
+ * in buf and return the number of bytes read. flags is always 0 in
+ * this version.
+ *
+ * If there is an error, return -1 and set error code
+ * WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error(). Wslay
+ * event-based API on the whole assumes non-blocking I/O. If the cause
+ * of error is EAGAIN or EWOULDBLOCK, set WSLAY_ERR_WOULDBLOCK
+ * instead. This is important because it tells wslay_event_recv() to
+ * stop receiving further data and return.
+ */
+typedef ssize_t (*wslay_event_recv_callback)(wslay_event_context_ptr ctx,
+ uint8_t *buf, size_t len,
+ int flags, void *user_data);
+
+/*
+ * Callback function invoked by wslay_event_send() when it wants to
+ * send more data to peer. The implementation of this callback
+ * function must send data at most len bytes to peer and return the
+ * number of bytes sent. flags is the bitwise OR of zero or more of
+ * the following flag:
+ *
+ * WSLAY_MSG_MORE
+ * There is more data to send
+ *
+ * It provides some hints to tune performance and behaviour.
+ *
+ * If there is an error, return -1 and set error code
+ * WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error(). Wslay
+ * event-based API on the whole assumes non-blocking I/O. If the cause
+ * of error is EAGAIN or EWOULDBLOCK, set WSLAY_ERR_WOULDBLOCK
+ * instead. This is important because it tells wslay_event_send() to
+ * stop sending data and return.
+ */
+typedef ssize_t (*wslay_event_send_callback)(wslay_event_context_ptr ctx,
+ const uint8_t *data, size_t len,
+ int flags, void *user_data);
+
+/*
+ * Callback function invoked by wslay_event_send() when it wants new
+ * mask key. As described in RFC6455, only the traffic from WebSocket
+ * client is masked, so this callback function is only needed if an
+ * event-based API is initialized for WebSocket client use.
+ */
+typedef int (*wslay_event_genmask_callback)(wslay_event_context_ptr ctx,
+ uint8_t *buf, size_t len,
+ void *user_data);
+
+struct wslay_event_callbacks {
+ wslay_event_recv_callback recv_callback;
+ wslay_event_send_callback send_callback;
+ wslay_event_genmask_callback genmask_callback;
+ wslay_event_on_frame_recv_start_callback on_frame_recv_start_callback;
+ wslay_event_on_frame_recv_chunk_callback on_frame_recv_chunk_callback;
+ wslay_event_on_frame_recv_end_callback on_frame_recv_end_callback;
+ wslay_event_on_msg_recv_callback on_msg_recv_callback;
+};
+
+/*
+ * Initializes ctx as WebSocket Server. user_data is an arbitrary
+ * pointer, which is directly passed to each callback functions as
+ * user_data argument.
+ *
+ * On success, returns 0. On error, returns one of following negative
+ * values:
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ */
+int wslay_event_context_server_init
+(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks, void *user_data);
+
+/*
+ * Initializes ctx as WebSocket client. user_data is an arbitrary
+ * pointer, which is directly passed to each callback functions as
+ * user_data argument.
+ *
+ * On success, returns 0. On error, returns one of following negative
+ * values:
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ */
+int wslay_event_context_client_init
+(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks, void *user_data);
+
+/*
+ * Releases allocated resources for ctx.
+ */
+void wslay_event_context_free(wslay_event_context_ptr ctx);
+
+/*
+ * Sets a bit mask of allowed reserved bits.
+ * Currently only permitted values are WSLAY_RSV1_BIT to allow PMCE
+ * extension (see RFC-7692) or WSLAY_RSV_NONE to disable.
+ *
+ * Default: WSLAY_RSV_NONE
+ */
+void wslay_event_config_set_allowed_rsv_bits(wslay_event_context_ptr ctx,
+ uint8_t rsv);
+
+/*
+ * Enables or disables buffering of an entire message for non-control
+ * frames. If val is 0, buffering is enabled. Otherwise, buffering is
+ * disabled. If wslay_event_on_msg_recv_callback is invoked when
+ * buffering is disabled, the msg_length member of struct
+ * wslay_event_on_msg_recv_arg is set to 0.
+ *
+ * The control frames are always buffered regardless of this function call.
+ *
+ * This function must not be used after the first invocation of
+ * wslay_event_recv() function.
+ */
+void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val);
+
+/*
+ * Sets maximum length of a message that can be received. The length
+ * of message is checked by wslay_event_recv() function. If the length
+ * of a message is larger than this value, reading operation is
+ * disabled (same effect with wslay_event_shutdown_read() call) and
+ * close control frame with WSLAY_CODE_MESSAGE_TOO_BIG is queued. If
+ * buffering for non-control frames is disabled, the library checks
+ * each frame payload length and does not check length of entire
+ * message.
+ *
+ * The default value is (1u << 31)-1.
+ */
+void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
+ uint64_t val);
+
+/*
+ * Sets callbacks to ctx. The callbacks previouly set by this function
+ * or wslay_event_context_server_init() or
+ * wslay_event_context_client_init() are replaced with callbacks.
+ */
+void wslay_event_config_set_callbacks
+(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
+
+/*
+ * Receives messages from peer. When receiving
+ * messages, it uses wslay_event_recv_callback function. Single call
+ * of this function receives multiple messages until
+ * wslay_event_recv_callback function sets error code
+ * WSLAY_ERR_WOULDBLOCK.
+ *
+ * When close control frame is received, this function automatically
+ * queues close control frame. Also this function calls
+ * wslay_event_set_read_enabled() with second argument 0 to disable
+ * further read from peer.
+ *
+ * When ping control frame is received, this function automatically
+ * queues pong control frame.
+ *
+ * In case of a fatal errror which leads to negative return code, this
+ * function calls wslay_event_set_read_enabled() with second argument
+ * 0 to disable further read from peer.
+ *
+ * wslay_event_recv() returns 0 if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * WSLAY_ERR_CALLBACK_FAILURE
+ * User defined callback function is failed.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ *
+ * When negative error code is returned, application must not make any
+ * further call of wslay_event_recv() and must close WebSocket
+ * connection.
+ */
+int wslay_event_recv(wslay_event_context_ptr ctx);
+
+/*
+ * Sends queued messages to peer. When sending a
+ * message, it uses wslay_event_send_callback function. Single call of
+ * wslay_event_send() sends multiple messages until
+ * wslay_event_send_callback sets error code WSLAY_ERR_WOULDBLOCK.
+ *
+ * If ctx is initialized for WebSocket client use, wslay_event_send()
+ * uses wslay_event_genmask_callback to get new mask key.
+ *
+ * When a message queued using wslay_event_queue_fragmented_msg() is
+ * sent, wslay_event_send() invokes
+ * wslay_event_fragmented_msg_callback for that message.
+ *
+ * After close control frame is sent, this function calls
+ * wslay_event_set_write_enabled() with second argument 0 to disable
+ * further transmission to peer.
+ *
+ * If there are any pending messages, wslay_event_want_write() returns
+ * 1, otherwise returns 0.
+ *
+ * In case of a fatal errror which leads to negative return code, this
+ * function calls wslay_event_set_write_enabled() with second argument
+ * 0 to disable further transmission to peer.
+ *
+ * wslay_event_send() returns 0 if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * WSLAY_ERR_CALLBACK_FAILURE
+ * User defined callback function is failed.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ *
+ * When negative error code is returned, application must not make any
+ * further call of wslay_event_send() and must close WebSocket
+ * connection.
+ */
+int wslay_event_send(wslay_event_context_ptr ctx);
+
+struct wslay_event_msg {
+ uint8_t opcode;
+ const uint8_t *msg;
+ size_t msg_length;
+};
+
+/*
+ * Queues message specified in arg.
+ *
+ * This function supports both control and non-control messages and
+ * the given message is sent without fragmentation. If fragmentation
+ * is needed, use wslay_event_queue_fragmented_msg() function instead.
+ *
+ * This function just queues a message and does not send
+ * it. wslay_event_send() function call sends these queued messages.
+ *
+ * wslay_event_queue_msg() returns 0 if it succeeds, or returns the
+ * following negative error codes:
+ *
+ * WSLAY_ERR_NO_MORE_MSG
+ * Could not queue given message. The one of possible reason is that
+ * close control frame has been queued/sent and no further queueing
+ * message is not allowed.
+ *
+ * WSLAY_ERR_INVALID_ARGUMENT
+ * The given message is invalid.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ */
+int wslay_event_queue_msg(wslay_event_context_ptr ctx,
+ const struct wslay_event_msg *arg);
+
+/*
+ * Extended version of wslay_event_queue_msg which allows to set reserved bits.
+ */
+int wslay_event_queue_msg_ex(wslay_event_context_ptr ctx,
+ const struct wslay_event_msg *arg, uint8_t rsv);
+
+/*
+ * Specify "source" to generate message.
+ */
+union wslay_event_msg_source {
+ int fd;
+ void *data;
+};
+
+/*
+ * Callback function called by wslay_event_send() to read message data
+ * from source. The implementation of
+ * wslay_event_fragmented_msg_callback must store at most len bytes of
+ * data to buf and return the number of stored bytes. If all data is
+ * read (i.e., EOF), set *eof to 1. If no data can be generated at the
+ * moment, return 0. If there is an error, return -1 and set error
+ * code WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error().
+ */
+typedef ssize_t (*wslay_event_fragmented_msg_callback)
+(wslay_event_context_ptr ctx,
+ uint8_t *buf, size_t len, const union wslay_event_msg_source *source,
+ int *eof, void *user_data);
+
+struct wslay_event_fragmented_msg {
+ /* opcode */
+ uint8_t opcode;
+ /* "source" to generate message data */
+ union wslay_event_msg_source source;
+ /* Callback function to read message data from source. */
+ wslay_event_fragmented_msg_callback read_callback;
+};
+
+/*
+ * Queues a fragmented message specified in arg.
+ *
+ * This function supports non-control messages only. For control frames,
+ * use wslay_event_queue_msg() or wslay_event_queue_close().
+ *
+ * This function just queues a message and does not send
+ * it. wslay_event_send() function call sends these queued messages.
+ *
+ * wslay_event_queue_fragmented_msg() returns 0 if it succeeds, or
+ * returns the following negative error codes:
+ *
+ * WSLAY_ERR_NO_MORE_MSG
+ * Could not queue given message. The one of possible reason is that
+ * close control frame has been queued/sent and no further queueing
+ * message is not allowed.
+ *
+ * WSLAY_ERR_INVALID_ARGUMENT
+ * The given message is invalid.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ */
+int wslay_event_queue_fragmented_msg
+(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
+
+/*
+ * Extended version of wslay_event_queue_fragmented_msg which allows to set
+ * reserved bits.
+ */
+int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
+ const struct wslay_event_fragmented_msg *arg, uint8_t rsv);
+
+/*
+ * Queues close control frame. This function is provided just for
+ * convenience. wslay_event_queue_msg() can queue a close control
+ * frame as well. status_code is the status code of close control
+ * frame. reason is the close reason encoded in UTF-8. reason_length
+ * is the length of reason in bytes. reason_length must be less than
+ * 123 bytes.
+ *
+ * If status_code is 0, reason and reason_length is not used and close
+ * control frame with zero-length payload will be queued.
+ *
+ * This function just queues a message and does not send
+ * it. wslay_event_send() function call sends these queued messages.
+ *
+ * wslay_event_queue_close() returns 0 if it succeeds, or returns the
+ * following negative error codes:
+ *
+ * WSLAY_ERR_NO_MORE_MSG
+ * Could not queue given message. The one of possible reason is that
+ * close control frame has been queued/sent and no further queueing
+ * message is not allowed.
+ *
+ * WSLAY_ERR_INVALID_ARGUMENT
+ * The given message is invalid.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ */
+int wslay_event_queue_close(wslay_event_context_ptr ctx,
+ uint16_t status_code,
+ const uint8_t *reason, size_t reason_length);
+
+/*
+ * Sets error code to tell the library there is an error. This
+ * function is typically used in user defined callback functions. See
+ * the description of callback function to know which error code
+ * should be used.
+ */
+void wslay_event_set_error(wslay_event_context_ptr ctx, int val);
+
+/*
+ * Query whehter the library want to read more data from peer.
+ *
+ * wslay_event_want_read() returns 1 if the library want to read more
+ * data from peer, or returns 0.
+ */
+int wslay_event_want_read(wslay_event_context_ptr ctx);
+
+/*
+ * Query whehter the library want to send more data to peer.
+ *
+ * wslay_event_want_write() returns 1 if the library want to send more
+ * data to peer, or returns 0.
+ */
+int wslay_event_want_write(wslay_event_context_ptr ctx);
+
+/*
+ * Prevents the event-based API context from reading any further data
+ * from peer.
+ *
+ * This function may be used with wslay_event_queue_close() if the
+ * application detects error in the data received and wants to fail
+ * WebSocket connection.
+ */
+void wslay_event_shutdown_read(wslay_event_context_ptr ctx);
+
+/*
+ * Prevents the event-based API context from sending any further data
+ * to peer.
+ */
+void wslay_event_shutdown_write(wslay_event_context_ptr ctx);
+
+/*
+ * Returns 1 if the event-based API context allows read operation, or
+ * return 0.
+ *
+ * After wslay_event_shutdown_read() is called,
+ * wslay_event_get_read_enabled() returns 0.
+ */
+int wslay_event_get_read_enabled(wslay_event_context_ptr ctx);
+
+/*
+ * Returns 1 if the event-based API context allows write operation, or
+ * return 0.
+ *
+ * After wslay_event_shutdown_write() is called,
+ * wslay_event_get_write_enabled() returns 0.
+ */
+int wslay_event_get_write_enabled(wslay_event_context_ptr ctx);
+
+/*
+ * Returns 1 if a close control frame has been received from peer, or
+ * returns 0.
+ */
+int wslay_event_get_close_received(wslay_event_context_ptr ctx);
+
+/*
+ * Returns 1 if a close control frame has been sent to peer, or
+ * returns 0.
+ */
+int wslay_event_get_close_sent(wslay_event_context_ptr ctx);
+
+/*
+ * Returns status code received in close control frame. If no close
+ * control frame has not been received, returns
+ * WSLAY_CODE_ABNORMAL_CLOSURE. If received close control frame has no
+ * status code, returns WSLAY_CODE_NO_STATUS_RCVD.
+ */
+uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx);
+
+/*
+ * Returns status code sent in close control frame. If no close
+ * control frame has not been sent, returns
+ * WSLAY_CODE_ABNORMAL_CLOSURE. If sent close control frame has no
+ * status code, returns WSLAY_CODE_NO_STATUS_RCVD.
+ */
+uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx);
+
+/*
+ * Returns the number of queued messages.
+ */
+size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx);
+
+/*
+ * Returns the sum of queued message length. It only counts the
+ * message length queued using wslay_event_queue_msg() or
+ * wslay_event_queue_close().
+ */
+size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WSLAY_H */
diff --git a/thirdparty/wslay/includes/wslay/wslayver.h b/thirdparty/wslay/includes/wslay/wslayver.h
new file mode 100644
index 0000000000..2c3e282e9d
--- /dev/null
+++ b/thirdparty/wslay/includes/wslay/wslayver.h
@@ -0,0 +1,31 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAYVER_H
+#define WSLAYVER_H
+
+/* Version number of wslay release */
+#define WSLAY_VERSION "1.1.0"
+
+#endif /* WSLAYVER_H */
diff --git a/thirdparty/wslay/msvcfix.diff b/thirdparty/wslay/msvcfix.diff
new file mode 100644
index 0000000000..28721844f4
--- /dev/null
+++ b/thirdparty/wslay/msvcfix.diff
@@ -0,0 +1,17 @@
+diff --git a/thirdparty/wslay/includes/wslay/wslay.h b/thirdparty/wslay/includes/wslay/wslay.h
+index 2fde81a4e..9c751b05b 100644
+--- a/thirdparty/wslay/includes/wslay/wslay.h
++++ b/thirdparty/wslay/includes/wslay/wslay.h
+@@ -33,6 +33,12 @@ extern "C" {
+ #include <stdlib.h>
+ #include <sys/types.h>
+
++/* GODOT ADDITTION */
++#if defined(_MSC_VER)
++#include <BaseTsd.h>
++typedef SSIZE_T ssize_t;
++#endif
++/* GODOT END */
+
+ /*
+ * wslay/wslayver.h is generated from wslay/wslayver.h.in by
diff --git a/thirdparty/wslay/wslay_event.c b/thirdparty/wslay/wslay_event.c
new file mode 100644
index 0000000000..57415c51e0
--- /dev/null
+++ b/thirdparty/wslay/wslay_event.c
@@ -0,0 +1,1027 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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.
+ */
+#include "wslay_event.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "wslay_queue.h"
+#include "wslay_frame.h"
+#include "wslay_net.h"
+/* Start of utf8 dfa */
+/* Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+ * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+ *
+ * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+ *
+ * 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.
+ */
+#define UTF8_ACCEPT 0
+#define UTF8_REJECT 12
+
+static const uint8_t utf8d[] = {
+ /*
+ * The first part of the table maps bytes to character classes that
+ * to reduce the size of the transition table and create bitmasks.
+ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ /*
+ * The second part is a transition table that maps a combination
+ * of a state of the automaton and a character class to a state.
+ */
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+};
+
+static uint32_t
+decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
+ uint32_t type = utf8d[byte];
+
+ *codep = (*state != UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xff >> type) & (byte);
+
+ *state = utf8d[256 + *state + type];
+ return *state;
+}
+
+/* End of utf8 dfa */
+
+static ssize_t wslay_event_frame_recv_callback(uint8_t *buf, size_t len,
+ int flags, void *user_data)
+{
+ struct wslay_event_frame_user_data *e =
+ (struct wslay_event_frame_user_data*)user_data;
+ return e->ctx->callbacks.recv_callback(e->ctx, buf, len, flags, e->user_data);
+}
+
+static ssize_t wslay_event_frame_send_callback(const uint8_t *data, size_t len,
+ int flags, void *user_data)
+{
+ struct wslay_event_frame_user_data *e =
+ (struct wslay_event_frame_user_data*)user_data;
+ return e->ctx->callbacks.send_callback(e->ctx, data, len, flags,
+ e->user_data);
+}
+
+static int wslay_event_frame_genmask_callback(uint8_t *buf, size_t len,
+ void *user_data)
+{
+ struct wslay_event_frame_user_data *e =
+ (struct wslay_event_frame_user_data*)user_data;
+ return e->ctx->callbacks.genmask_callback(e->ctx, buf, len, e->user_data);
+}
+
+static int wslay_event_byte_chunk_init
+(struct wslay_event_byte_chunk **chunk, size_t len)
+{
+ *chunk = (struct wslay_event_byte_chunk*)malloc
+ (sizeof(struct wslay_event_byte_chunk));
+ if(*chunk == NULL) {
+ return WSLAY_ERR_NOMEM;
+ }
+ memset(*chunk, 0, sizeof(struct wslay_event_byte_chunk));
+ if(len) {
+ (*chunk)->data = (uint8_t*)malloc(len);
+ if((*chunk)->data == NULL) {
+ free(*chunk);
+ return WSLAY_ERR_NOMEM;
+ }
+ (*chunk)->data_length = len;
+ }
+ return 0;
+}
+
+static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c)
+{
+ if(!c) {
+ return;
+ }
+ free(c->data);
+ free(c);
+}
+
+static void wslay_event_byte_chunk_copy(struct wslay_event_byte_chunk *c,
+ size_t off,
+ const uint8_t *data, size_t data_length)
+{
+ memcpy(c->data+off, data, data_length);
+}
+
+static void wslay_event_imsg_set(struct wslay_event_imsg *m,
+ uint8_t fin, uint8_t rsv, uint8_t opcode)
+{
+ m->fin = fin;
+ m->rsv = rsv;
+ m->opcode = opcode;
+ m->msg_length = 0;
+}
+
+static void wslay_event_imsg_chunks_free(struct wslay_event_imsg *m)
+{
+ if(!m->chunks) {
+ return;
+ }
+ while(!wslay_queue_empty(m->chunks)) {
+ wslay_event_byte_chunk_free(wslay_queue_top(m->chunks));
+ wslay_queue_pop(m->chunks);
+ }
+}
+
+static void wslay_event_imsg_reset(struct wslay_event_imsg *m)
+{
+ m->opcode = 0xffu;
+ m->utf8state = UTF8_ACCEPT;
+ wslay_event_imsg_chunks_free(m);
+}
+
+static int wslay_event_imsg_append_chunk(struct wslay_event_imsg *m, size_t len)
+{
+ if(len == 0) {
+ return 0;
+ } else {
+ int r;
+ struct wslay_event_byte_chunk *chunk;
+ if((r = wslay_event_byte_chunk_init(&chunk, len)) != 0) {
+ return r;
+ }
+ if((r = wslay_queue_push(m->chunks, chunk)) != 0) {
+ return r;
+ }
+ m->msg_length += len;
+ return 0;
+ }
+}
+
+static int wslay_event_omsg_non_fragmented_init
+(struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
+ const uint8_t *msg, size_t msg_length)
+{
+ *m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
+ if(!*m) {
+ return WSLAY_ERR_NOMEM;
+ }
+ memset(*m, 0, sizeof(struct wslay_event_omsg));
+ (*m)->fin = 1;
+ (*m)->opcode = opcode;
+ (*m)->rsv = rsv;
+ (*m)->type = WSLAY_NON_FRAGMENTED;
+ if(msg_length) {
+ (*m)->data = (uint8_t*)malloc(msg_length);
+ if(!(*m)->data) {
+ free(*m);
+ return WSLAY_ERR_NOMEM;
+ }
+ memcpy((*m)->data, msg, msg_length);
+ (*m)->data_length = msg_length;
+ }
+ return 0;
+}
+
+static int wslay_event_omsg_fragmented_init
+(struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
+ const union wslay_event_msg_source source,
+ wslay_event_fragmented_msg_callback read_callback)
+{
+ *m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
+ if(!*m) {
+ return WSLAY_ERR_NOMEM;
+ }
+ memset(*m, 0, sizeof(struct wslay_event_omsg));
+ (*m)->opcode = opcode;
+ (*m)->rsv = rsv;
+ (*m)->type = WSLAY_FRAGMENTED;
+ (*m)->source = source;
+ (*m)->read_callback = read_callback;
+ return 0;
+}
+
+static void wslay_event_omsg_free(struct wslay_event_omsg *m)
+{
+ if(!m) {
+ return;
+ }
+ free(m->data);
+ free(m);
+}
+
+static uint8_t* wslay_event_flatten_queue(struct wslay_queue *queue, size_t len)
+{
+ if(len == 0) {
+ return NULL;
+ } else {
+ size_t off = 0;
+ uint8_t *buf = (uint8_t*)malloc(len);
+ if(!buf) {
+ return NULL;
+ }
+ while(!wslay_queue_empty(queue)) {
+ struct wslay_event_byte_chunk *chunk = wslay_queue_top(queue);
+ memcpy(buf+off, chunk->data, chunk->data_length);
+ off += chunk->data_length;
+ wslay_event_byte_chunk_free(chunk);
+ wslay_queue_pop(queue);
+ assert(off <= len);
+ }
+ assert(len == off);
+ return buf;
+ }
+}
+
+static int wslay_event_is_msg_queueable(wslay_event_context_ptr ctx)
+{
+ return ctx->write_enabled && (ctx->close_status & WSLAY_CLOSE_QUEUED) == 0;
+}
+
+int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
+ const uint8_t *reason, size_t reason_length)
+{
+ if(!wslay_event_is_msg_queueable(ctx)) {
+ return WSLAY_ERR_NO_MORE_MSG;
+ } else if(reason_length > 123) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ } else {
+ uint8_t msg[128];
+ size_t msg_length;
+ struct wslay_event_msg arg;
+ uint16_t ncode;
+ int r;
+ if(status_code == 0) {
+ msg_length = 0;
+ } else {
+ ncode = htons(status_code);
+ memcpy(msg, &ncode, 2);
+ if(reason_length) {
+ memcpy(msg+2, reason, reason_length);
+ }
+ msg_length = reason_length+2;
+ }
+ arg.opcode = WSLAY_CONNECTION_CLOSE;
+ arg.msg = msg;
+ arg.msg_length = msg_length;
+ r = wslay_event_queue_msg(ctx, &arg);
+ if(r == 0) {
+ ctx->close_status |= WSLAY_CLOSE_QUEUED;
+ }
+ return r;
+ }
+}
+
+static int wslay_event_queue_close_wrapper
+(wslay_event_context_ptr ctx, uint16_t status_code,
+ const uint8_t *reason, size_t reason_length)
+{
+ int r;
+ ctx->read_enabled = 0;
+ if((r = wslay_event_queue_close(ctx, status_code, reason, reason_length)) &&
+ r != WSLAY_ERR_NO_MORE_MSG) {
+ return r;
+ }
+ return 0;
+}
+
+static int wslay_event_verify_rsv_bits(wslay_event_context_ptr ctx, uint8_t rsv)
+{
+ return ((rsv & ~ctx->allowed_rsv_bits) == 0);
+}
+
+int wslay_event_queue_msg(wslay_event_context_ptr ctx,
+ const struct wslay_event_msg *arg)
+{
+ return wslay_event_queue_msg_ex(ctx, arg, WSLAY_RSV_NONE);
+}
+
+int wslay_event_queue_msg_ex(wslay_event_context_ptr ctx,
+ const struct wslay_event_msg *arg, uint8_t rsv)
+{
+ int r;
+ struct wslay_event_omsg *omsg;
+ if(!wslay_event_is_msg_queueable(ctx)) {
+ return WSLAY_ERR_NO_MORE_MSG;
+ }
+ /* RSV1 is not allowed for control frames */
+ if((wslay_is_ctrl_frame(arg->opcode) &&
+ (arg->msg_length > 125 || wslay_get_rsv1(rsv)))
+ || !wslay_event_verify_rsv_bits(ctx, rsv)) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if((r = wslay_event_omsg_non_fragmented_init
+ (&omsg, arg->opcode, rsv, arg->msg, arg->msg_length)) != 0) {
+ return r;
+ }
+ if(wslay_is_ctrl_frame(arg->opcode)) {
+ if((r = wslay_queue_push(ctx->send_ctrl_queue, omsg)) != 0) {
+ return r;
+ }
+ } else {
+ if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
+ return r;
+ }
+ }
+ ++ctx->queued_msg_count;
+ ctx->queued_msg_length += arg->msg_length;
+ return 0;
+}
+
+int wslay_event_queue_fragmented_msg
+(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg)
+{
+ return wslay_event_queue_fragmented_msg_ex(ctx, arg, WSLAY_RSV_NONE);
+}
+
+int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
+ const struct wslay_event_fragmented_msg *arg, uint8_t rsv)
+{
+ int r;
+ struct wslay_event_omsg *omsg;
+ if(!wslay_event_is_msg_queueable(ctx)) {
+ return WSLAY_ERR_NO_MORE_MSG;
+ }
+ if(wslay_is_ctrl_frame(arg->opcode) ||
+ !wslay_event_verify_rsv_bits(ctx, rsv)) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if((r = wslay_event_omsg_fragmented_init
+ (&omsg, arg->opcode, rsv, arg->source, arg->read_callback)) != 0) {
+ return r;
+ }
+ if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
+ return r;
+ }
+ ++ctx->queued_msg_count;
+ return 0;
+}
+
+void wslay_event_config_set_callbacks
+(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks)
+{
+ ctx->callbacks = *callbacks;
+}
+
+static int wslay_event_context_init
+(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks,
+ void *user_data)
+{
+ int i, r;
+ struct wslay_frame_callbacks frame_callbacks = {
+ wslay_event_frame_send_callback,
+ wslay_event_frame_recv_callback,
+ wslay_event_frame_genmask_callback
+ };
+ *ctx = (wslay_event_context_ptr)malloc(sizeof(struct wslay_event_context));
+ if(!*ctx) {
+ return WSLAY_ERR_NOMEM;
+ }
+ memset(*ctx, 0, sizeof(struct wslay_event_context));
+ wslay_event_config_set_callbacks(*ctx, callbacks);
+ (*ctx)->user_data = user_data;
+ (*ctx)->frame_user_data.ctx = *ctx;
+ (*ctx)->frame_user_data.user_data = user_data;
+ if((r = wslay_frame_context_init(&(*ctx)->frame_ctx, &frame_callbacks,
+ &(*ctx)->frame_user_data)) != 0) {
+ wslay_event_context_free(*ctx);
+ return r;
+ }
+ (*ctx)->read_enabled = (*ctx)->write_enabled = 1;
+ (*ctx)->send_queue = wslay_queue_new();
+ if(!(*ctx)->send_queue) {
+ wslay_event_context_free(*ctx);
+ return WSLAY_ERR_NOMEM;
+ }
+ (*ctx)->send_ctrl_queue = wslay_queue_new();
+ if(!(*ctx)->send_ctrl_queue) {
+ wslay_event_context_free(*ctx);
+ return WSLAY_ERR_NOMEM;
+ }
+ (*ctx)->queued_msg_count = 0;
+ (*ctx)->queued_msg_length = 0;
+ for(i = 0; i < 2; ++i) {
+ wslay_event_imsg_reset(&(*ctx)->imsgs[i]);
+ (*ctx)->imsgs[i].chunks = wslay_queue_new();
+ if(!(*ctx)->imsgs[i].chunks) {
+ wslay_event_context_free(*ctx);
+ return WSLAY_ERR_NOMEM;
+ }
+ }
+ (*ctx)->imsg = &(*ctx)->imsgs[0];
+ (*ctx)->obufmark = (*ctx)->obuflimit = (*ctx)->obuf;
+ (*ctx)->status_code_sent = WSLAY_CODE_ABNORMAL_CLOSURE;
+ (*ctx)->status_code_recv = WSLAY_CODE_ABNORMAL_CLOSURE;
+ (*ctx)->max_recv_msg_length = (1u << 31)-1;
+ return 0;
+}
+
+int wslay_event_context_server_init
+(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks,
+ void *user_data)
+{
+ int r;
+ if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
+ return r;
+ }
+ (*ctx)->server = 1;
+ return 0;
+}
+
+int wslay_event_context_client_init
+(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks,
+ void *user_data)
+{
+ int r;
+ if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
+ return r;
+ }
+ (*ctx)->server = 0;
+ return 0;
+}
+
+void wslay_event_context_free(wslay_event_context_ptr ctx)
+{
+ int i;
+ if(!ctx) {
+ return;
+ }
+ for(i = 0; i < 2; ++i) {
+ wslay_event_imsg_chunks_free(&ctx->imsgs[i]);
+ wslay_queue_free(ctx->imsgs[i].chunks);
+ }
+ if(ctx->send_queue) {
+ while(!wslay_queue_empty(ctx->send_queue)) {
+ wslay_event_omsg_free(wslay_queue_top(ctx->send_queue));
+ wslay_queue_pop(ctx->send_queue);
+ }
+ wslay_queue_free(ctx->send_queue);
+ }
+ if(ctx->send_ctrl_queue) {
+ while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
+ wslay_event_omsg_free(wslay_queue_top(ctx->send_ctrl_queue));
+ wslay_queue_pop(ctx->send_ctrl_queue);
+ }
+ wslay_queue_free(ctx->send_ctrl_queue);
+ }
+ wslay_frame_context_free(ctx->frame_ctx);
+ wslay_event_omsg_free(ctx->omsg);
+ free(ctx);
+}
+
+static void wslay_event_call_on_frame_recv_start_callback
+(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
+{
+ if(ctx->callbacks.on_frame_recv_start_callback) {
+ struct wslay_event_on_frame_recv_start_arg arg;
+ arg.fin = iocb->fin;
+ arg.rsv = iocb->rsv;
+ arg.opcode = iocb->opcode;
+ arg.payload_length = iocb->payload_length;
+ ctx->callbacks.on_frame_recv_start_callback(ctx, &arg, ctx->user_data);
+ }
+}
+
+static void wslay_event_call_on_frame_recv_chunk_callback
+(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
+{
+ if(ctx->callbacks.on_frame_recv_chunk_callback) {
+ struct wslay_event_on_frame_recv_chunk_arg arg;
+ arg.data = iocb->data;
+ arg.data_length = iocb->data_length;
+ ctx->callbacks.on_frame_recv_chunk_callback(ctx, &arg, ctx->user_data);
+ }
+}
+
+static void wslay_event_call_on_frame_recv_end_callback
+(wslay_event_context_ptr ctx)
+{
+ if(ctx->callbacks.on_frame_recv_end_callback) {
+ ctx->callbacks.on_frame_recv_end_callback(ctx, ctx->user_data);
+ }
+}
+
+static int wslay_event_is_valid_status_code(uint16_t status_code)
+{
+ return (1000 <= status_code && status_code <= 1011 &&
+ status_code != 1004 && status_code != 1005 && status_code != 1006) ||
+ (3000 <= status_code && status_code <= 4999);
+}
+
+static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx)
+{
+ return (ctx->config & WSLAY_CONFIG_NO_BUFFERING) > 0;
+}
+
+int wslay_event_recv(wslay_event_context_ptr ctx)
+{
+ struct wslay_frame_iocb iocb;
+ ssize_t r;
+ while(ctx->read_enabled) {
+ memset(&iocb, 0, sizeof(iocb));
+ r = wslay_frame_recv(ctx->frame_ctx, &iocb);
+ if(r >= 0) {
+ int new_frame = 0;
+ /* RSV1 is not allowed on control and continuation frames */
+ if((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) ||
+ (wslay_get_rsv1(iocb.rsv) && (wslay_is_ctrl_frame(iocb.opcode) ||
+ iocb.opcode == WSLAY_CONTINUATION_FRAME)) ||
+ (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ if(ctx->imsg->opcode == 0xffu) {
+ if(iocb.opcode == WSLAY_TEXT_FRAME ||
+ iocb.opcode == WSLAY_BINARY_FRAME ||
+ iocb.opcode == WSLAY_CONNECTION_CLOSE ||
+ iocb.opcode == WSLAY_PING ||
+ iocb.opcode == WSLAY_PONG) {
+ wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
+ new_frame = 1;
+ } else {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ } else if(ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) {
+ if(iocb.opcode == WSLAY_CONTINUATION_FRAME) {
+ ctx->imsg->fin = iocb.fin;
+ } else if(iocb.opcode == WSLAY_CONNECTION_CLOSE ||
+ iocb.opcode == WSLAY_PING ||
+ iocb.opcode == WSLAY_PONG) {
+ ctx->imsg = &ctx->imsgs[1];
+ wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
+ } else {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ new_frame = 1;
+ }
+ if(new_frame) {
+ if(ctx->imsg->msg_length+iocb.payload_length >
+ ctx->max_recv_msg_length) {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ ctx->ipayloadlen = iocb.payload_length;
+ wslay_event_call_on_frame_recv_start_callback(ctx, &iocb);
+ if(!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
+ if((r = wslay_event_imsg_append_chunk(ctx->imsg,
+ iocb.payload_length)) != 0) {
+ ctx->read_enabled = 0;
+ return r;
+ }
+ }
+ }
+ /* If RSV1 bit is set then it is too early for utf-8 validation */
+ if((!wslay_get_rsv1(ctx->imsg->rsv) &&
+ ctx->imsg->opcode == WSLAY_TEXT_FRAME) ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ size_t i;
+ if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ i = 2;
+ } else {
+ i = 0;
+ }
+ for(; i < iocb.data_length; ++i) {
+ uint32_t codep;
+ if(decode(&ctx->imsg->utf8state, &codep,
+ iocb.data[i]) == UTF8_REJECT) {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ }
+ }
+ if(ctx->imsg->utf8state == UTF8_REJECT) {
+ break;
+ }
+ wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb);
+ if(iocb.data_length > 0) {
+ if(!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
+ struct wslay_event_byte_chunk *chunk;
+ chunk = wslay_queue_tail(ctx->imsg->chunks);
+ wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff,
+ iocb.data, iocb.data_length);
+ }
+ ctx->ipayloadoff += iocb.data_length;
+ }
+ if(ctx->ipayloadoff == ctx->ipayloadlen) {
+ if(ctx->imsg->fin &&
+ (ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) &&
+ ctx->imsg->utf8state != UTF8_ACCEPT) {
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ wslay_event_call_on_frame_recv_end_callback(ctx);
+ if(ctx->imsg->fin) {
+ if(ctx->callbacks.on_msg_recv_callback ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE ||
+ ctx->imsg->opcode == WSLAY_PING) {
+ struct wslay_event_on_msg_recv_arg arg;
+ uint16_t status_code = 0;
+ uint8_t *msg = NULL;
+ size_t msg_length = 0;
+ if(!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
+ msg = wslay_event_flatten_queue(ctx->imsg->chunks,
+ ctx->imsg->msg_length);
+ if(ctx->imsg->msg_length && !msg) {
+ ctx->read_enabled = 0;
+ return WSLAY_ERR_NOMEM;
+ }
+ msg_length = ctx->imsg->msg_length;
+ }
+ if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ const uint8_t *reason;
+ size_t reason_length;
+ if(ctx->imsg->msg_length >= 2) {
+ memcpy(&status_code, msg, 2);
+ status_code = ntohs(status_code);
+ if(!wslay_event_is_valid_status_code(status_code)) {
+ free(msg);
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return r;
+ }
+ break;
+ }
+ reason = msg+2;
+ reason_length = ctx->imsg->msg_length-2;
+ } else {
+ reason = NULL;
+ reason_length = 0;
+ }
+ ctx->close_status |= WSLAY_CLOSE_RECEIVED;
+ ctx->status_code_recv =
+ status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
+ if((r = wslay_event_queue_close_wrapper
+ (ctx, status_code, reason, reason_length)) != 0) {
+ free(msg);
+ return r;
+ }
+ } else if(ctx->imsg->opcode == WSLAY_PING) {
+ struct wslay_event_msg arg;
+ arg.opcode = WSLAY_PONG;
+ arg.msg = msg;
+ arg.msg_length = ctx->imsg->msg_length;
+ if((r = wslay_event_queue_msg(ctx, &arg)) &&
+ r != WSLAY_ERR_NO_MORE_MSG) {
+ ctx->read_enabled = 0;
+ free(msg);
+ return r;
+ }
+ }
+ if(ctx->callbacks.on_msg_recv_callback) {
+ arg.rsv = ctx->imsg->rsv;
+ arg.opcode = ctx->imsg->opcode;
+ arg.msg = msg;
+ arg.msg_length = msg_length;
+ arg.status_code = status_code;
+ ctx->error = 0;
+ ctx->callbacks.on_msg_recv_callback(ctx, &arg, ctx->user_data);
+ }
+ free(msg);
+ }
+ wslay_event_imsg_reset(ctx->imsg);
+ if(ctx->imsg == &ctx->imsgs[1]) {
+ ctx->imsg = &ctx->imsgs[0];
+ }
+ }
+ ctx->ipayloadlen = ctx->ipayloadoff = 0;
+ }
+ } else {
+ if(r != WSLAY_ERR_WANT_READ ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
+ if((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) {
+ return r;
+ }
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void wslay_event_on_non_fragmented_msg_popped
+(wslay_event_context_ptr ctx)
+{
+ ctx->omsg->fin = 1;
+ ctx->opayloadlen = ctx->omsg->data_length;
+ ctx->opayloadoff = 0;
+}
+
+static struct wslay_event_omsg* wslay_event_send_ctrl_queue_pop
+(wslay_event_context_ptr ctx)
+{
+ /*
+ * If Close control frame is queued, we don't send any control frame
+ * other than Close.
+ */
+ if(ctx->close_status & WSLAY_CLOSE_QUEUED) {
+ while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
+ struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
+ wslay_queue_pop(ctx->send_ctrl_queue);
+ if(msg->opcode == WSLAY_CONNECTION_CLOSE) {
+ return msg;
+ } else {
+ wslay_event_omsg_free(msg);
+ }
+ }
+ return NULL;
+ } else {
+ struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
+ wslay_queue_pop(ctx->send_ctrl_queue);
+ return msg;
+ }
+}
+
+int wslay_event_send(wslay_event_context_ptr ctx)
+{
+ struct wslay_frame_iocb iocb;
+ ssize_t r;
+ while(ctx->write_enabled &&
+ (!wslay_queue_empty(ctx->send_queue) ||
+ !wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg)) {
+ if(!ctx->omsg) {
+ if(wslay_queue_empty(ctx->send_ctrl_queue)) {
+ ctx->omsg = wslay_queue_top(ctx->send_queue);
+ wslay_queue_pop(ctx->send_queue);
+ } else {
+ ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
+ if(ctx->omsg == NULL) {
+ break;
+ }
+ }
+ if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ wslay_event_on_non_fragmented_msg_popped(ctx);
+ }
+ } else if(!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
+ ctx->frame_ctx->ostate == PREP_HEADER &&
+ !wslay_queue_empty(ctx->send_ctrl_queue)) {
+ if((r = wslay_queue_push_front(ctx->send_queue, ctx->omsg)) != 0) {
+ ctx->write_enabled = 0;
+ return r;
+ }
+ ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
+ if(ctx->omsg == NULL) {
+ break;
+ }
+ /* ctrl message has WSLAY_NON_FRAGMENTED */
+ wslay_event_on_non_fragmented_msg_popped(ctx);
+ }
+ if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fin = 1;
+ iocb.opcode = ctx->omsg->opcode;
+ iocb.rsv = ctx->omsg->rsv;
+ iocb.mask = ctx->server^1;
+ iocb.data = ctx->omsg->data+ctx->opayloadoff;
+ iocb.data_length = ctx->opayloadlen-ctx->opayloadoff;
+ iocb.payload_length = ctx->opayloadlen;
+ r = wslay_frame_send(ctx->frame_ctx, &iocb);
+ if(r >= 0) {
+ ctx->opayloadoff += r;
+ if(ctx->opayloadoff == ctx->opayloadlen) {
+ --ctx->queued_msg_count;
+ ctx->queued_msg_length -= ctx->omsg->data_length;
+ if(ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ uint16_t status_code = 0;
+ ctx->write_enabled = 0;
+ ctx->close_status |= WSLAY_CLOSE_SENT;
+ if(ctx->omsg->data_length >= 2) {
+ memcpy(&status_code, ctx->omsg->data, 2);
+ status_code = ntohs(status_code);
+ }
+ ctx->status_code_sent =
+ status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
+ }
+ wslay_event_omsg_free(ctx->omsg);
+ ctx->omsg = NULL;
+ } else {
+ break;
+ }
+ } else {
+ if(r != WSLAY_ERR_WANT_WRITE ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
+ ctx->write_enabled = 0;
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ break;
+ }
+ } else {
+ if(ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
+ int eof = 0;
+ r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
+ &ctx->omsg->source,
+ &eof, ctx->user_data);
+ if(r == 0) {
+ break;
+ } else if(r < 0) {
+ ctx->write_enabled = 0;
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ ctx->obuflimit = ctx->obuf+r;
+ if(eof) {
+ ctx->omsg->fin = 1;
+ }
+ ctx->opayloadlen = r;
+ ctx->opayloadoff = 0;
+ }
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fin = ctx->omsg->fin;
+ iocb.opcode = ctx->omsg->opcode;
+ iocb.rsv = ctx->omsg->rsv;
+ iocb.mask = ctx->server ? 0 : 1;
+ iocb.data = ctx->obufmark;
+ iocb.data_length = ctx->obuflimit-ctx->obufmark;
+ iocb.payload_length = ctx->opayloadlen;
+ r = wslay_frame_send(ctx->frame_ctx, &iocb);
+ if(r >= 0) {
+ ctx->obufmark += r;
+ if(ctx->obufmark == ctx->obuflimit) {
+ ctx->obufmark = ctx->obuflimit = ctx->obuf;
+ if(ctx->omsg->fin) {
+ --ctx->queued_msg_count;
+ wslay_event_omsg_free(ctx->omsg);
+ ctx->omsg = NULL;
+ } else {
+ ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
+ /* RSV1 is not set on continuation frames */
+ ctx->omsg->rsv = ctx->omsg->rsv & ~WSLAY_RSV1_BIT;
+ }
+ } else {
+ break;
+ }
+ } else {
+ if(r != WSLAY_ERR_WANT_WRITE ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK &&
+ ctx->error != 0)) {
+ ctx->write_enabled = 0;
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+void wslay_event_set_error(wslay_event_context_ptr ctx, int val)
+{
+ ctx->error = val;
+}
+
+int wslay_event_want_read(wslay_event_context_ptr ctx)
+{
+ return ctx->read_enabled;
+}
+
+int wslay_event_want_write(wslay_event_context_ptr ctx)
+{
+ return ctx->write_enabled &&
+ (!wslay_queue_empty(ctx->send_queue) ||
+ !wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg);
+}
+
+void wslay_event_shutdown_read(wslay_event_context_ptr ctx)
+{
+ ctx->read_enabled = 0;
+}
+
+void wslay_event_shutdown_write(wslay_event_context_ptr ctx)
+{
+ ctx->write_enabled = 0;
+}
+
+int wslay_event_get_read_enabled(wslay_event_context_ptr ctx)
+{
+ return ctx->read_enabled;
+}
+
+int wslay_event_get_write_enabled(wslay_event_context_ptr ctx)
+{
+ return ctx->write_enabled;
+}
+
+int wslay_event_get_close_received(wslay_event_context_ptr ctx)
+{
+ return (ctx->close_status & WSLAY_CLOSE_RECEIVED) > 0;
+}
+
+int wslay_event_get_close_sent(wslay_event_context_ptr ctx)
+{
+ return (ctx->close_status & WSLAY_CLOSE_SENT) > 0;
+}
+
+void wslay_event_config_set_allowed_rsv_bits(wslay_event_context_ptr ctx,
+ uint8_t rsv)
+{
+ /* We currently only allow WSLAY_RSV1_BIT or WSLAY_RSV_NONE */
+ ctx->allowed_rsv_bits = rsv & WSLAY_RSV1_BIT;
+}
+
+void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val)
+{
+ if(val) {
+ ctx->config |= WSLAY_CONFIG_NO_BUFFERING;
+ } else {
+ ctx->config &= ~WSLAY_CONFIG_NO_BUFFERING;
+ }
+}
+
+void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
+ uint64_t val)
+{
+ ctx->max_recv_msg_length = val;
+}
+
+uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx)
+{
+ return ctx->status_code_recv;
+}
+
+uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx)
+{
+ return ctx->status_code_sent;
+}
+
+size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx)
+{
+ return ctx->queued_msg_count;
+}
+
+size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx)
+{
+ return ctx->queued_msg_length;
+}
diff --git a/thirdparty/wslay/wslay_event.h b/thirdparty/wslay/wslay_event.h
new file mode 100644
index 0000000000..36feb9036d
--- /dev/null
+++ b/thirdparty/wslay/wslay_event.h
@@ -0,0 +1,142 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_EVENT_H
+#define WSLAY_EVENT_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <wslay/wslay.h>
+
+struct wslay_stack;
+struct wslay_queue;
+
+struct wslay_event_byte_chunk {
+ uint8_t *data;
+ size_t data_length;
+};
+
+struct wslay_event_imsg {
+ uint8_t fin;
+ uint8_t rsv;
+ uint8_t opcode;
+ uint32_t utf8state;
+ struct wslay_queue *chunks;
+ size_t msg_length;
+};
+
+enum wslay_event_msg_type {
+ WSLAY_NON_FRAGMENTED,
+ WSLAY_FRAGMENTED
+};
+
+struct wslay_event_omsg {
+ uint8_t fin;
+ uint8_t opcode;
+ uint8_t rsv;
+ enum wslay_event_msg_type type;
+
+ uint8_t *data;
+ size_t data_length;
+
+ union wslay_event_msg_source source;
+ wslay_event_fragmented_msg_callback read_callback;
+};
+
+struct wslay_event_frame_user_data {
+ wslay_event_context_ptr ctx;
+ void *user_data;
+};
+
+enum wslay_event_close_status {
+ WSLAY_CLOSE_RECEIVED = 1 << 0,
+ WSLAY_CLOSE_QUEUED = 1 << 1,
+ WSLAY_CLOSE_SENT = 1 << 2
+};
+
+enum wslay_event_config {
+ WSLAY_CONFIG_NO_BUFFERING = 1 << 0
+};
+
+struct wslay_event_context {
+ /* config status, bitwise OR of enum wslay_event_config values*/
+ uint32_t config;
+ /* maximum message length that can be received */
+ uint64_t max_recv_msg_length;
+ /* 1 if initialized for server, otherwise 0 */
+ uint8_t server;
+ /* bitwise OR of enum wslay_event_close_status values */
+ uint8_t close_status;
+ /* status code in received close control frame */
+ uint16_t status_code_recv;
+ /* status code in sent close control frame */
+ uint16_t status_code_sent;
+ wslay_frame_context_ptr frame_ctx;
+ /* 1 if reading is enabled, otherwise 0. Upon receiving close
+ control frame this value set to 0. If any errors in read
+ operation will also set this value to 0. */
+ uint8_t read_enabled;
+ /* 1 if writing is enabled, otherwise 0 Upon completing sending
+ close control frame, this value set to 0. If any errors in write
+ opration will also set this value to 0. */
+ uint8_t write_enabled;
+ /* imsg buffer to allow interleaved control frame between
+ non-control frames. */
+ struct wslay_event_imsg imsgs[2];
+ /* Pointer to imsgs to indicate current used buffer. */
+ struct wslay_event_imsg *imsg;
+ /* payload length of frame currently being received. */
+ uint64_t ipayloadlen;
+ /* next byte offset of payload currently being received. */
+ uint64_t ipayloadoff;
+ /* error value set by user callback */
+ int error;
+ /* Pointer to the message currently being sent. NULL if no message
+ is currently sent. */
+ struct wslay_event_omsg *omsg;
+ /* Queue for non-control frames */
+ struct wslay_queue/*<wslay_omsg*>*/ *send_queue;
+ /* Queue for control frames */
+ struct wslay_queue/*<wslay_omsg*>*/ *send_ctrl_queue;
+ /* Size of send_queue + size of send_ctrl_queue */
+ size_t queued_msg_count;
+ /* The sum of message length in send_queue */
+ size_t queued_msg_length;
+ /* Buffer used for fragmented messages */
+ uint8_t obuf[4096];
+ uint8_t *obuflimit;
+ uint8_t *obufmark;
+ /* payload length of frame currently being sent. */
+ uint64_t opayloadlen;
+ /* next byte offset of payload currently being sent. */
+ uint64_t opayloadoff;
+ struct wslay_event_callbacks callbacks;
+ struct wslay_event_frame_user_data frame_user_data;
+ void *user_data;
+ uint8_t allowed_rsv_bits;
+};
+
+#endif /* WSLAY_EVENT_H */
diff --git a/thirdparty/wslay/wslay_frame.c b/thirdparty/wslay/wslay_frame.c
new file mode 100644
index 0000000000..445e750ca5
--- /dev/null
+++ b/thirdparty/wslay/wslay_frame.c
@@ -0,0 +1,340 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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.
+ */
+#include "wslay_frame.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "wslay_net.h"
+
+#define wslay_min(A, B) (((A) < (B)) ? (A) : (B))
+
+int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
+ const struct wslay_frame_callbacks *callbacks,
+ void *user_data)
+{
+ *ctx = (wslay_frame_context_ptr)malloc(sizeof(struct wslay_frame_context));
+ if(*ctx == NULL) {
+ return -1;
+ }
+ memset(*ctx, 0, sizeof(struct wslay_frame_context));
+ (*ctx)->istate = RECV_HEADER1;
+ (*ctx)->ireqread = 2;
+ (*ctx)->ostate = PREP_HEADER;
+ (*ctx)->user_data = user_data;
+ (*ctx)->ibufmark = (*ctx)->ibuflimit = (*ctx)->ibuf;
+ (*ctx)->callbacks = *callbacks;
+ return 0;
+}
+
+void wslay_frame_context_free(wslay_frame_context_ptr ctx)
+{
+ free(ctx);
+}
+
+ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb)
+{
+ if(iocb->data_length > iocb->payload_length) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if(ctx->ostate == PREP_HEADER) {
+ uint8_t *hdptr = ctx->oheader;
+ memset(ctx->oheader, 0, sizeof(ctx->oheader));
+ *hdptr |= (iocb->fin << 7) & 0x80u;
+ *hdptr |= (iocb->rsv << 4) & 0x70u;
+ *hdptr |= iocb->opcode & 0xfu;
+ ++hdptr;
+ *hdptr |= (iocb->mask << 7) & 0x80u;
+ if(wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if(iocb->payload_length < 126) {
+ *hdptr |= iocb->payload_length;
+ ++hdptr;
+ } else if(iocb->payload_length < (1 << 16)) {
+ uint16_t len = htons(iocb->payload_length);
+ *hdptr |= 126;
+ ++hdptr;
+ memcpy(hdptr, &len, 2);
+ hdptr += 2;
+ } else if(iocb->payload_length < (1ull << 63)) {
+ uint64_t len = hton64(iocb->payload_length);
+ *hdptr |= 127;
+ ++hdptr;
+ memcpy(hdptr, &len, 8);
+ hdptr += 8;
+ } else {
+ /* Too large payload length */
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if(iocb->mask) {
+ if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
+ ctx->user_data) != 0) {
+ return WSLAY_ERR_INVALID_CALLBACK;
+ } else {
+ ctx->omask = 1;
+ memcpy(hdptr, ctx->omaskkey, 4);
+ hdptr += 4;
+ }
+ }
+ ctx->ostate = SEND_HEADER;
+ ctx->oheadermark = ctx->oheader;
+ ctx->oheaderlimit = hdptr;
+ ctx->opayloadlen = iocb->payload_length;
+ ctx->opayloadoff = 0;
+ }
+ if(ctx->ostate == SEND_HEADER) {
+ ptrdiff_t len = ctx->oheaderlimit-ctx->oheadermark;
+ ssize_t r;
+ int flags = 0;
+ if(iocb->data_length > 0) {
+ flags |= WSLAY_MSG_MORE;
+ };
+ r = ctx->callbacks.send_callback(ctx->oheadermark, len, flags,
+ ctx->user_data);
+ if(r > 0) {
+ if(r > len) {
+ return WSLAY_ERR_INVALID_CALLBACK;
+ } else {
+ ctx->oheadermark += r;
+ if(ctx->oheadermark == ctx->oheaderlimit) {
+ ctx->ostate = SEND_PAYLOAD;
+ } else {
+ return WSLAY_ERR_WANT_WRITE;
+ }
+ }
+ } else {
+ return WSLAY_ERR_WANT_WRITE;
+ }
+ }
+ if(ctx->ostate == SEND_PAYLOAD) {
+ size_t totallen = 0;
+ if(iocb->data_length > 0) {
+ if(ctx->omask) {
+ uint8_t temp[4096];
+ const uint8_t *datamark = iocb->data,
+ *datalimit = iocb->data+iocb->data_length;
+ while(datamark < datalimit) {
+ size_t datalen = datalimit - datamark;
+ const uint8_t *writelimit = datamark+
+ wslay_min(sizeof(temp), datalen);
+ size_t writelen = writelimit-datamark;
+ ssize_t r;
+ size_t i;
+ for(i = 0; i < writelen; ++i) {
+ temp[i] = datamark[i]^ctx->omaskkey[(ctx->opayloadoff+i)%4];
+ }
+ r = ctx->callbacks.send_callback(temp, writelen, 0, ctx->user_data);
+ if(r > 0) {
+ if((size_t)r > writelen) {
+ return WSLAY_ERR_INVALID_CALLBACK;
+ } else {
+ datamark += r;
+ ctx->opayloadoff += r;
+ totallen += r;
+ }
+ } else {
+ if(totallen > 0) {
+ break;
+ } else {
+ return WSLAY_ERR_WANT_WRITE;
+ }
+ }
+ }
+ } else {
+ ssize_t r;
+ r = ctx->callbacks.send_callback(iocb->data, iocb->data_length, 0,
+ ctx->user_data);
+ if(r > 0) {
+ if((size_t)r > iocb->data_length) {
+ return WSLAY_ERR_INVALID_CALLBACK;
+ } else {
+ ctx->opayloadoff += r;
+ totallen = r;
+ }
+ } else {
+ return WSLAY_ERR_WANT_WRITE;
+ }
+ }
+ }
+ if(ctx->opayloadoff == ctx->opayloadlen) {
+ ctx->ostate = PREP_HEADER;
+ }
+ return totallen;
+ }
+ return WSLAY_ERR_INVALID_ARGUMENT;
+}
+
+static void wslay_shift_ibuf(wslay_frame_context_ptr ctx)
+{
+ ptrdiff_t len = ctx->ibuflimit-ctx->ibufmark;
+ memmove(ctx->ibuf, ctx->ibufmark, len);
+ ctx->ibuflimit = ctx->ibuf+len;
+ ctx->ibufmark = ctx->ibuf;
+}
+
+static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
+{
+ ssize_t r;
+ if(ctx->ibufmark != ctx->ibuf) {
+ wslay_shift_ibuf(ctx);
+ }
+ r = ctx->callbacks.recv_callback
+ (ctx->ibuflimit, ctx->ibuf+sizeof(ctx->ibuf)-ctx->ibuflimit,
+ 0, ctx->user_data);
+ if(r > 0) {
+ ctx->ibuflimit += r;
+ } else {
+ r = WSLAY_ERR_WANT_READ;
+ }
+ return r;
+}
+
+#define WSLAY_AVAIL_IBUF(ctx) ((size_t)(ctx->ibuflimit - ctx->ibufmark))
+
+ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb)
+{
+ ssize_t r;
+ if(ctx->istate == RECV_HEADER1) {
+ uint8_t fin, opcode, rsv, payloadlen;
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if((r = wslay_recv(ctx)) <= 0) {
+ return r;
+ }
+ }
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ return WSLAY_ERR_WANT_READ;
+ }
+ fin = (ctx->ibufmark[0] >> 7) & 1;
+ rsv = (ctx->ibufmark[0] >> 4) & 7;
+ opcode = ctx->ibufmark[0] & 0xfu;
+ ctx->iom.opcode = opcode;
+ ctx->iom.fin = fin;
+ ctx->iom.rsv = rsv;
+ ++ctx->ibufmark;
+ ctx->imask = (ctx->ibufmark[0] >> 7) & 1;
+ payloadlen = ctx->ibufmark[0] & 0x7fu;
+ ++ctx->ibufmark;
+ if(wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
+ return WSLAY_ERR_PROTO;
+ }
+ if(payloadlen == 126) {
+ ctx->istate = RECV_EXT_PAYLOADLEN;
+ ctx->ireqread = 2;
+ } else if(payloadlen == 127) {
+ ctx->istate = RECV_EXT_PAYLOADLEN;
+ ctx->ireqread = 8;
+ } else {
+ ctx->ipayloadlen = payloadlen;
+ ctx->ipayloadoff = 0;
+ if(ctx->imask) {
+ ctx->istate = RECV_MASKKEY;
+ ctx->ireqread = 4;
+ } else {
+ ctx->istate = RECV_PAYLOAD;
+ }
+ }
+ }
+ if(ctx->istate == RECV_EXT_PAYLOADLEN) {
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if((r = wslay_recv(ctx)) <= 0) {
+ return r;
+ }
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ return WSLAY_ERR_WANT_READ;
+ }
+ }
+ ctx->ipayloadlen = 0;
+ ctx->ipayloadoff = 0;
+ memcpy((uint8_t*)&ctx->ipayloadlen+(8-ctx->ireqread),
+ ctx->ibufmark, ctx->ireqread);
+ ctx->ipayloadlen = ntoh64(ctx->ipayloadlen);
+ ctx->ibufmark += ctx->ireqread;
+ if(ctx->ireqread == 8) {
+ if(ctx->ipayloadlen < (1 << 16) ||
+ ctx->ipayloadlen & (1ull << 63)) {
+ return WSLAY_ERR_PROTO;
+ }
+ } else if(ctx->ipayloadlen < 126) {
+ return WSLAY_ERR_PROTO;
+ }
+ if(ctx->imask) {
+ ctx->istate = RECV_MASKKEY;
+ ctx->ireqread = 4;
+ } else {
+ ctx->istate = RECV_PAYLOAD;
+ }
+ }
+ if(ctx->istate == RECV_MASKKEY) {
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if((r = wslay_recv(ctx)) <= 0) {
+ return r;
+ }
+ if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ return WSLAY_ERR_WANT_READ;
+ }
+ }
+ memcpy(ctx->imaskkey, ctx->ibufmark, 4);
+ ctx->ibufmark += 4;
+ ctx->istate = RECV_PAYLOAD;
+ }
+ if(ctx->istate == RECV_PAYLOAD) {
+ uint8_t *readlimit, *readmark;
+ uint64_t rempayloadlen = ctx->ipayloadlen-ctx->ipayloadoff;
+ if(WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
+ if((r = wslay_recv(ctx)) <= 0) {
+ return r;
+ }
+ }
+ readmark = ctx->ibufmark;
+ readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen ?
+ ctx->ibuflimit : ctx->ibufmark+rempayloadlen;
+ if(ctx->imask) {
+ for(; ctx->ibufmark != readlimit;
+ ++ctx->ibufmark, ++ctx->ipayloadoff) {
+ ctx->ibufmark[0] ^= ctx->imaskkey[ctx->ipayloadoff % 4];
+ }
+ } else {
+ ctx->ibufmark = readlimit;
+ ctx->ipayloadoff += readlimit-readmark;
+ }
+ iocb->fin = ctx->iom.fin;
+ iocb->rsv = ctx->iom.rsv;
+ iocb->opcode = ctx->iom.opcode;
+ iocb->payload_length = ctx->ipayloadlen;
+ iocb->mask = ctx->imask;
+ iocb->data = readmark;
+ iocb->data_length = ctx->ibufmark-readmark;
+ if(ctx->ipayloadlen == ctx->ipayloadoff) {
+ ctx->istate = RECV_HEADER1;
+ ctx->ireqread = 2;
+ }
+ return iocb->data_length;
+ }
+ return WSLAY_ERR_INVALID_ARGUMENT;
+}
diff --git a/thirdparty/wslay/wslay_frame.h b/thirdparty/wslay/wslay_frame.h
new file mode 100644
index 0000000000..6a75858cc7
--- /dev/null
+++ b/thirdparty/wslay/wslay_frame.h
@@ -0,0 +1,76 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_FRAME_H
+#define WSLAY_FRAME_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <wslay/wslay.h>
+
+enum wslay_frame_state {
+ PREP_HEADER,
+ SEND_HEADER,
+ SEND_PAYLOAD,
+ RECV_HEADER1,
+ RECV_PAYLOADLEN,
+ RECV_EXT_PAYLOADLEN,
+ RECV_MASKKEY,
+ RECV_PAYLOAD
+};
+
+struct wslay_frame_opcode_memo {
+ uint8_t fin;
+ uint8_t opcode;
+ uint8_t rsv;
+};
+
+struct wslay_frame_context {
+ uint8_t ibuf[4096];
+ uint8_t *ibufmark;
+ uint8_t *ibuflimit;
+ struct wslay_frame_opcode_memo iom;
+ uint64_t ipayloadlen;
+ uint64_t ipayloadoff;
+ uint8_t imask;
+ uint8_t imaskkey[4];
+ enum wslay_frame_state istate;
+ size_t ireqread;
+
+ uint8_t oheader[14];
+ uint8_t *oheadermark;
+ uint8_t *oheaderlimit;
+ uint64_t opayloadlen;
+ uint64_t opayloadoff;
+ uint8_t omask;
+ uint8_t omaskkey[4];
+ enum wslay_frame_state ostate;
+
+ struct wslay_frame_callbacks callbacks;
+ void *user_data;
+};
+
+#endif /* WSLAY_FRAME_H */
diff --git a/thirdparty/wslay/wslay_net.c b/thirdparty/wslay/wslay_net.c
new file mode 100644
index 0000000000..d3867c21fb
--- /dev/null
+++ b/thirdparty/wslay/wslay_net.c
@@ -0,0 +1,36 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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.
+ */
+#include "wslay_net.h"
+
+#ifndef WORDS_BIGENDIAN
+
+uint64_t wslay_byteswap64(uint64_t x)
+{
+ uint64_t u = ntohl(x & 0xffffffffllu);
+ uint64_t l = ntohl(x >> 32);
+ return (u << 32) | l;
+}
+
+#endif /* !WORDS_BIGENDIAN */
diff --git a/thirdparty/wslay/wslay_net.h b/thirdparty/wslay/wslay_net.h
new file mode 100644
index 0000000000..2310870156
--- /dev/null
+++ b/thirdparty/wslay/wslay_net.h
@@ -0,0 +1,54 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_NET_H
+#define WSLAY_NET_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <wslay/wslay.h>
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif /* HAVE_ARPA_INET_H */
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+/* For Mingw build */
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif /* HAVE_WINSOCK2_H */
+
+#ifdef WORDS_BIGENDIAN
+# define ntoh64(x) (x)
+# define hton64(x) (x)
+#else /* !WORDS_BIGENDIAN */
+uint64_t wslay_byteswap64(uint64_t x);
+# define ntoh64(x) wslay_byteswap64(x)
+# define hton64(x) wslay_byteswap64(x)
+#endif /* !WORDS_BIGENDIAN */
+
+#endif /* WSLAY_NET_H */
diff --git a/thirdparty/wslay/wslay_queue.c b/thirdparty/wslay/wslay_queue.c
new file mode 100644
index 0000000000..8d2669687d
--- /dev/null
+++ b/thirdparty/wslay/wslay_queue.c
@@ -0,0 +1,117 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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.
+ */
+#include "wslay_queue.h"
+
+#include <string.h>
+#include <assert.h>
+
+struct wslay_queue* wslay_queue_new(void)
+{
+ struct wslay_queue *queue = (struct wslay_queue*)malloc
+ (sizeof(struct wslay_queue));
+ if(!queue) {
+ return NULL;
+ }
+ queue->top = queue->tail = NULL;
+ return queue;
+}
+
+void wslay_queue_free(struct wslay_queue *queue)
+{
+ if(!queue) {
+ return;
+ } else {
+ struct wslay_queue_cell *p = queue->top;
+ while(p) {
+ struct wslay_queue_cell *next = p->next;
+ free(p);
+ p = next;
+ }
+ free(queue);
+ }
+}
+
+int wslay_queue_push(struct wslay_queue *queue, void *data)
+{
+ struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
+ (sizeof(struct wslay_queue_cell));
+ if(!new_cell) {
+ return WSLAY_ERR_NOMEM;
+ }
+ new_cell->data = data;
+ new_cell->next = NULL;
+ if(queue->tail) {
+ queue->tail->next = new_cell;
+ queue->tail = new_cell;
+
+ } else {
+ queue->top = queue->tail = new_cell;
+ }
+ return 0;
+}
+
+int wslay_queue_push_front(struct wslay_queue *queue, void *data)
+{
+ struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
+ (sizeof(struct wslay_queue_cell));
+ if(!new_cell) {
+ return WSLAY_ERR_NOMEM;
+ }
+ new_cell->data = data;
+ new_cell->next = queue->top;
+ queue->top = new_cell;
+ if(!queue->tail) {
+ queue->tail = queue->top;
+ }
+ return 0;
+}
+
+void wslay_queue_pop(struct wslay_queue *queue)
+{
+ struct wslay_queue_cell *top = queue->top;
+ assert(top);
+ queue->top = top->next;
+ if(top == queue->tail) {
+ queue->tail = NULL;
+ }
+ free(top);
+}
+
+void* wslay_queue_top(struct wslay_queue *queue)
+{
+ assert(queue->top);
+ return queue->top->data;
+}
+
+void* wslay_queue_tail(struct wslay_queue *queue)
+{
+ assert(queue->tail);
+ return queue->tail->data;
+}
+
+int wslay_queue_empty(struct wslay_queue *queue)
+{
+ return queue->top == NULL;
+}
diff --git a/thirdparty/wslay/wslay_queue.h b/thirdparty/wslay/wslay_queue.h
new file mode 100644
index 0000000000..55e78a042e
--- /dev/null
+++ b/thirdparty/wslay/wslay_queue.h
@@ -0,0 +1,53 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_QUEUE_H
+#define WSLAY_QUEUE_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <wslay/wslay.h>
+
+struct wslay_queue_cell {
+ void *data;
+ struct wslay_queue_cell *next;
+};
+
+struct wslay_queue {
+ struct wslay_queue_cell *top;
+ struct wslay_queue_cell *tail;
+};
+
+struct wslay_queue* wslay_queue_new(void);
+void wslay_queue_free(struct wslay_queue *queue);
+int wslay_queue_push(struct wslay_queue *queue, void *data);
+int wslay_queue_push_front(struct wslay_queue *queue, void *data);
+void wslay_queue_pop(struct wslay_queue *queue);
+void* wslay_queue_top(struct wslay_queue *queue);
+void* wslay_queue_tail(struct wslay_queue *queue);
+int wslay_queue_empty(struct wslay_queue *queue);
+
+#endif /* WSLAY_QUEUE_H */
diff --git a/thirdparty/wslay/wslay_stack.c b/thirdparty/wslay/wslay_stack.c
new file mode 100644
index 0000000000..0e05d74031
--- /dev/null
+++ b/thirdparty/wslay/wslay_stack.c
@@ -0,0 +1,86 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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.
+ */
+#include "wslay_stack.h"
+
+#include <string.h>
+#include <assert.h>
+
+struct wslay_stack* wslay_stack_new()
+{
+ struct wslay_stack *stack = (struct wslay_stack*)malloc
+ (sizeof(struct wslay_stack));
+ if(!stack) {
+ return NULL;
+ }
+ stack->top = NULL;
+ return stack;
+}
+
+void wslay_stack_free(struct wslay_stack *stack)
+{
+ struct wslay_stack_cell *p;
+ if(!stack) {
+ return;
+ }
+ p = stack->top;
+ while(p) {
+ struct wslay_stack_cell *next = p->next;
+ free(p);
+ p = next;
+ }
+ free(stack);
+}
+
+int wslay_stack_push(struct wslay_stack *stack, void *data)
+{
+ struct wslay_stack_cell *new_cell = (struct wslay_stack_cell*)malloc
+ (sizeof(struct wslay_stack_cell));
+ if(!new_cell) {
+ return WSLAY_ERR_NOMEM;
+ }
+ new_cell->data = data;
+ new_cell->next = stack->top;
+ stack->top = new_cell;
+ return 0;
+}
+
+void wslay_stack_pop(struct wslay_stack *stack)
+{
+ struct wslay_stack_cell *top = stack->top;
+ assert(top);
+ stack->top = top->next;
+ free(top);
+}
+
+void* wslay_stack_top(struct wslay_stack *stack)
+{
+ assert(stack->top);
+ return stack->top->data;
+}
+
+int wslay_stack_empty(struct wslay_stack *stack)
+{
+ return stack->top == NULL;
+}
diff --git a/thirdparty/wslay/wslay_stack.h b/thirdparty/wslay/wslay_stack.h
new file mode 100644
index 0000000000..16e4e968eb
--- /dev/null
+++ b/thirdparty/wslay/wslay_stack.h
@@ -0,0 +1,50 @@
+/*
+ * Wslay - The WebSocket Library
+ *
+ * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ *
+ * 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 WSLAY_STACK_H
+#define WSLAY_STACK_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <wslay/wslay.h>
+
+struct wslay_stack_cell {
+ void *data;
+ struct wslay_stack_cell *next;
+};
+
+struct wslay_stack {
+ struct wslay_stack_cell *top;
+};
+
+struct wslay_stack* wslay_stack_new();
+void wslay_stack_free(struct wslay_stack *stack);
+int wslay_stack_push(struct wslay_stack *stack, void *data);
+void wslay_stack_pop(struct wslay_stack *stack);
+void* wslay_stack_top(struct wslay_stack *stack);
+int wslay_stack_empty(struct wslay_stack *stack);
+
+#endif /* WSLAY_STACK_H */