mirror of
https://github.com/aria2/aria2.git
synced 2024-12-02 14:33:44 +08:00
Update wslay
This commit is contained in:
parent
a151b5bcef
commit
63f6ed726e
85
deps/wslay/NEWS
vendored
85
deps/wslay/NEWS
vendored
@ -1,47 +1,82 @@
|
||||
wslay 1.0.0
|
||||
wslay 1.1.1
|
||||
===========
|
||||
|
||||
Release Note
|
||||
------------
|
||||
|
||||
This release fixes several build issues. Most changes were introduced
|
||||
by contributors. Thank you for all the contributions in this project.
|
||||
Because wslay is very stable since the previous release (more than 2
|
||||
years ago), we mark this release 1.0.0.
|
||||
This release fixes the bug that eof is not evaluated after the
|
||||
invocation of read_callback.
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
* Fix NULL check in wslay_frame_context_init.
|
||||
* Check for eof when read_callback returns 0 (GH-47)
|
||||
|
||||
Patch from Witchakorn Kamolpornwijit
|
||||
Patch from Robert Bragg
|
||||
|
||||
* the examples uses epoll and thus only be built on linux
|
||||
|
||||
|
||||
Patch from Kazuho Oku
|
||||
wslay 1.1.0
|
||||
===========
|
||||
|
||||
* build: allow one to build out-of-tree documentation
|
||||
Release Note
|
||||
------------
|
||||
|
||||
Patch from Vincent Bernat
|
||||
This release adds CMake build support and the ability to set and
|
||||
verify reserved bits. Build issue with nettle >= 3.4 was fixed.
|
||||
|
||||
* build: fix `./configure` when nettle is not present
|
||||
Changes
|
||||
-------
|
||||
|
||||
`PKG_CHECK_MODULES` will fail unless we give it an action to execute
|
||||
on failure. When nettle is not available, we set `have_nettle` to
|
||||
`no`.
|
||||
* Fix compilation of examples
|
||||
|
||||
Patch from Vincent Bernat
|
||||
Since 3.4 nettle defines base64_encode_raw like this:
|
||||
|
||||
* Adds the ability to override the version header include with a
|
||||
define. This enables projects to set the build version from the
|
||||
compile environment and avoid the need to generate the version
|
||||
header.
|
||||
void base64_encode_raw(char *dst, size_t length, const uint8_t *src);
|
||||
|
||||
Patch from Ben Vanik
|
||||
So examples have to be adjusted. More read at
|
||||
https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.4_release_20171119/NEWS#L49-53
|
||||
|
||||
* Improve http_handshake in fork-echoserver.
|
||||
Patch from Sergey Avseyev
|
||||
|
||||
Patch from Gurjeet Singh
|
||||
* check for 0 length before memcpy:
|
||||
|
||||
* Don't send any pending control frame other than Close control frame
|
||||
after Close is queued.
|
||||
.../wslay/lib/wslay_event.c:304:7: runtime error: null pointer passed as argument 2, which is declared to never be null
|
||||
|
||||
Patch from Anders Bakken
|
||||
|
||||
* Skip UTF-8 validation for PMCE fragments
|
||||
|
||||
If the message was marked with rsv1 on the initial frame then we
|
||||
should skip utf-8 validation on subsequent continuation frames as
|
||||
well.
|
||||
|
||||
Added test for this case.
|
||||
|
||||
Found by autobahn wstest tool.
|
||||
|
||||
Patch from Isaac Boukris
|
||||
|
||||
* Allow RSV1 bit in event-based API for PMCE - RFC 7692
|
||||
|
||||
Add a new function wslay_event_set_allowed_rsv_bits which only accpet
|
||||
RSV1 for now (or 0 to disable).
|
||||
|
||||
Skip UTF-8 validation on frames with RSV1 set as it is too early for that.
|
||||
|
||||
Add extended versions of wslay_event_queue_msg functions which also
|
||||
take the reserved bits to set for this message.
|
||||
|
||||
Patch from Isaac Boukris
|
||||
|
||||
* fixed missing malloc guard
|
||||
|
||||
Patch from Jakub Piskorz
|
||||
|
||||
* Fix argc check.
|
||||
|
||||
Patch from Anders Bakken
|
||||
|
||||
* CMake support
|
||||
|
||||
Patch from wonder-mice
|
||||
|
2
deps/wslay/README.rst
vendored
2
deps/wslay/README.rst
vendored
@ -1,7 +1,7 @@
|
||||
Wslay - The WebSocket library
|
||||
=============================
|
||||
|
||||
Project Web: https://github.com/tatsuhiro-t/wslay
|
||||
Project Web: https://tatsuhiro-t.github.io/wslay/
|
||||
|
||||
Wslay is a WebSocket library written in C.
|
||||
It implements the protocol version 13 described in
|
||||
|
14
deps/wslay/configure.ac
vendored
14
deps/wslay/configure.ac
vendored
@ -21,15 +21,15 @@ dnl LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([wslay], [1.0.1-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([wslay], [1.1.1], [t-tujikawa@users.sourceforge.net])
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT()
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
dnl See versioning rule:
|
||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 0)
|
||||
AC_SUBST(LT_CURRENT, 1)
|
||||
AC_SUBST(LT_REVISION, 1)
|
||||
AC_SUBST(LT_AGE, 0)
|
||||
AC_SUBST(LT_AGE, 1)
|
||||
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
@ -40,6 +40,14 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE()
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for command-line options
|
||||
AC_ARG_ENABLE([werror],
|
||||
[AS_HELP_STRING([--enable-werror],
|
||||
[Turn on compile time warnings])],
|
||||
[werror=$enableval], [werror=no])
|
||||
|
||||
dnl Checks for programs
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
411
deps/wslay/examples/echoserv.cc
vendored
411
deps/wslay/examples/echoserv.cc
vendored
@ -53,8 +53,7 @@
|
||||
#include <nettle/sha.h>
|
||||
#include <wslay/wslay.h>
|
||||
|
||||
int create_listen_socket(const char *service)
|
||||
{
|
||||
int create_listen_socket(const char *service) {
|
||||
struct addrinfo hints;
|
||||
int sfd = -1;
|
||||
int r;
|
||||
@ -64,27 +63,27 @@ int create_listen_socket(const char *service)
|
||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
||||
struct addrinfo *res;
|
||||
r = getaddrinfo(0, service, &hints, &res);
|
||||
if(r != 0) {
|
||||
if (r != 0) {
|
||||
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if(sfd == -1) {
|
||||
if (sfd == -1) {
|
||||
continue;
|
||||
}
|
||||
int val = 1;
|
||||
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
continue;
|
||||
}
|
||||
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||
break;
|
||||
}
|
||||
close(sfd);
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
if(listen(sfd, 16) == -1) {
|
||||
if (listen(sfd, 16) == -1) {
|
||||
perror("listen");
|
||||
close(sfd);
|
||||
return -1;
|
||||
@ -92,46 +91,45 @@ int create_listen_socket(const char *service)
|
||||
return sfd;
|
||||
}
|
||||
|
||||
int make_non_block(int fd)
|
||||
{
|
||||
int make_non_block(int fd) {
|
||||
int flags, r;
|
||||
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
|
||||
if(flags == -1) {
|
||||
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string sha1(const std::string& src)
|
||||
{
|
||||
std::string sha1(const std::string &src) {
|
||||
sha1_ctx ctx;
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
|
||||
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t *>(src.c_str()));
|
||||
uint8_t temp[SHA1_DIGEST_SIZE];
|
||||
sha1_digest(&ctx, SHA1_DIGEST_SIZE, temp);
|
||||
std::string res(&temp[0], &temp[SHA1_DIGEST_SIZE]);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string base64(const std::string& src)
|
||||
{
|
||||
std::string base64(const std::string &src) {
|
||||
base64_encode_ctx ctx;
|
||||
base64_encode_init(&ctx);
|
||||
int dstlen = BASE64_ENCODE_RAW_LENGTH(src.size());
|
||||
uint8_t *dst = new uint8_t[dstlen];
|
||||
base64_encode_raw(dst, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
|
||||
char *dst = new char[dstlen];
|
||||
base64_encode_raw(dst, src.size(),
|
||||
reinterpret_cast<const uint8_t *>(src.c_str()));
|
||||
std::string res(&dst[0], &dst[dstlen]);
|
||||
delete [] dst;
|
||||
delete[] dst;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string create_acceptkey(const std::string& clientkey)
|
||||
{
|
||||
std::string s = clientkey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
std::string create_acceptkey(const std::string &clientkey) {
|
||||
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
return base64(sha1(s));
|
||||
}
|
||||
|
||||
@ -144,12 +142,11 @@ public:
|
||||
virtual bool want_write() = 0;
|
||||
virtual int fd() const = 0;
|
||||
virtual bool finish() = 0;
|
||||
virtual EventHandler* next() = 0;
|
||||
virtual EventHandler *next() = 0;
|
||||
};
|
||||
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *data, size_t len, int flags,
|
||||
void *user_data);
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
|
||||
size_t len, int flags, void *user_data);
|
||||
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
||||
int flags, void *user_data);
|
||||
void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
@ -158,93 +155,71 @@ void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
|
||||
class EchoWebSocketHandler : public EventHandler {
|
||||
public:
|
||||
EchoWebSocketHandler(int fd)
|
||||
: fd_(fd)
|
||||
{
|
||||
EchoWebSocketHandler(int fd) : fd_(fd) {
|
||||
struct wslay_event_callbacks callbacks = {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
NULL, /* genmask_callback */
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_callback
|
||||
};
|
||||
recv_callback,
|
||||
send_callback,
|
||||
NULL, /* genmask_callback */
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_callback};
|
||||
wslay_event_context_server_init(&ctx_, &callbacks, this);
|
||||
}
|
||||
virtual ~EchoWebSocketHandler()
|
||||
{
|
||||
virtual ~EchoWebSocketHandler() {
|
||||
wslay_event_context_free(ctx_);
|
||||
shutdown(fd_, SHUT_WR);
|
||||
close(fd_);
|
||||
}
|
||||
virtual int on_read_event()
|
||||
{
|
||||
if(wslay_event_recv(ctx_) == 0) {
|
||||
virtual int on_read_event() {
|
||||
if (wslay_event_recv(ctx_) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
virtual int on_write_event()
|
||||
{
|
||||
if(wslay_event_send(ctx_) == 0) {
|
||||
virtual int on_write_event() {
|
||||
if (wslay_event_send(ctx_) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ssize_t send_data(const uint8_t *data, size_t len, int flags)
|
||||
{
|
||||
ssize_t send_data(const uint8_t *data, size_t len, int flags) {
|
||||
ssize_t r;
|
||||
int sflags = 0;
|
||||
#ifdef MSG_MORE
|
||||
if(flags & WSLAY_MSG_MORE) {
|
||||
if (flags & WSLAY_MSG_MORE) {
|
||||
sflags |= MSG_MORE;
|
||||
}
|
||||
#endif // MSG_MORE
|
||||
while((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR);
|
||||
while ((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
ssize_t recv_data(uint8_t *data, size_t len, int flags)
|
||||
{
|
||||
ssize_t recv_data(uint8_t *data, size_t len, int flags) {
|
||||
ssize_t r;
|
||||
while((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR);
|
||||
while ((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
virtual bool want_read()
|
||||
{
|
||||
return wslay_event_want_read(ctx_);
|
||||
}
|
||||
virtual bool want_write()
|
||||
{
|
||||
return wslay_event_want_write(ctx_);
|
||||
}
|
||||
virtual int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
virtual bool finish()
|
||||
{
|
||||
return !want_read() && !want_write();
|
||||
}
|
||||
virtual EventHandler* next()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual bool want_read() { return wslay_event_want_read(ctx_); }
|
||||
virtual bool want_write() { return wslay_event_want_write(ctx_); }
|
||||
virtual int fd() const { return fd_; }
|
||||
virtual bool finish() { return !want_read() && !want_write(); }
|
||||
virtual EventHandler *next() { return 0; }
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
wslay_event_context_ptr ctx_;
|
||||
};
|
||||
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
EchoWebSocketHandler *sv = (EchoWebSocketHandler*)user_data;
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
|
||||
size_t len, int flags, void *user_data) {
|
||||
EchoWebSocketHandler *sv = (EchoWebSocketHandler *)user_data;
|
||||
ssize_t r = sv->send_data(data, len, flags);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
@ -254,17 +229,16 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
}
|
||||
|
||||
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
EchoWebSocketHandler *sv = (EchoWebSocketHandler*)user_data;
|
||||
int flags, void *user_data) {
|
||||
EchoWebSocketHandler *sv = (EchoWebSocketHandler *)user_data;
|
||||
ssize_t r = sv->recv_data(data, len, flags);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
}
|
||||
} else if(r == 0) {
|
||||
} else if (r == 0) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
r = -1;
|
||||
}
|
||||
@ -273,50 +247,44 @@ ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
||||
|
||||
void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
if(!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {
|
||||
arg->opcode, arg->msg, arg->msg_length
|
||||
};
|
||||
void *user_data) {
|
||||
if (!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
|
||||
wslay_event_queue_msg(ctx, &msgarg);
|
||||
}
|
||||
}
|
||||
|
||||
class HttpHandshakeSendHandler : public EventHandler {
|
||||
public:
|
||||
HttpHandshakeSendHandler(int fd, const std::string& accept_key)
|
||||
: fd_(fd),
|
||||
resheaders_("HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: "+accept_key+"\r\n"
|
||||
"\r\n"),
|
||||
off_(0)
|
||||
{}
|
||||
virtual ~HttpHandshakeSendHandler()
|
||||
{
|
||||
if(fd_ != -1) {
|
||||
HttpHandshakeSendHandler(int fd, const std::string &accept_key)
|
||||
: fd_(fd),
|
||||
resheaders_("HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: " +
|
||||
accept_key +
|
||||
"\r\n"
|
||||
"\r\n"),
|
||||
off_(0) {}
|
||||
virtual ~HttpHandshakeSendHandler() {
|
||||
if (fd_ != -1) {
|
||||
shutdown(fd_, SHUT_WR);
|
||||
close(fd_);
|
||||
}
|
||||
}
|
||||
virtual int on_read_event()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int on_write_event()
|
||||
{
|
||||
while(1) {
|
||||
size_t len = resheaders_.size()-off_;
|
||||
if(len == 0) {
|
||||
virtual int on_read_event() { return 0; }
|
||||
virtual int on_write_event() {
|
||||
while (1) {
|
||||
size_t len = resheaders_.size() - off_;
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
ssize_t r;
|
||||
while((r = write(fd_, resheaders_.c_str()+off_, len)) == -1 &&
|
||||
errno == EINTR);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
while ((r = write(fd_, resheaders_.c_str() + off_, len)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
break;
|
||||
} else {
|
||||
perror("write");
|
||||
@ -328,25 +296,12 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual bool want_read()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool want_write()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
virtual bool finish()
|
||||
{
|
||||
return off_ == resheaders_.size();
|
||||
}
|
||||
virtual EventHandler* next()
|
||||
{
|
||||
if(finish()) {
|
||||
virtual bool want_read() { return false; }
|
||||
virtual bool want_write() { return true; }
|
||||
virtual int fd() const { return fd_; }
|
||||
virtual bool finish() { return off_ == resheaders_.size(); }
|
||||
virtual EventHandler *next() {
|
||||
if (finish()) {
|
||||
int fd = fd_;
|
||||
fd_ = -1;
|
||||
return new EchoWebSocketHandler(fd);
|
||||
@ -354,6 +309,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
std::string headers_;
|
||||
@ -363,79 +319,60 @@ private:
|
||||
|
||||
class HttpHandshakeRecvHandler : public EventHandler {
|
||||
public:
|
||||
HttpHandshakeRecvHandler(int fd)
|
||||
: fd_(fd)
|
||||
{}
|
||||
virtual ~HttpHandshakeRecvHandler()
|
||||
{
|
||||
if(fd_ != -1) {
|
||||
HttpHandshakeRecvHandler(int fd) : fd_(fd) {}
|
||||
virtual ~HttpHandshakeRecvHandler() {
|
||||
if (fd_ != -1) {
|
||||
close(fd_);
|
||||
}
|
||||
}
|
||||
virtual int on_read_event()
|
||||
{
|
||||
virtual int on_read_event() {
|
||||
char buf[4096];
|
||||
ssize_t r;
|
||||
std::string client_key;
|
||||
while(1) {
|
||||
while((r = read(fd_, buf, sizeof(buf))) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
if(errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
while (1) {
|
||||
while ((r = read(fd_, buf, sizeof(buf))) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
break;
|
||||
} else {
|
||||
perror("read");
|
||||
return -1;
|
||||
}
|
||||
} else if(r == 0) {
|
||||
} else if (r == 0) {
|
||||
std::cerr << "http_upgrade: Got EOF" << std::endl;
|
||||
return -1;
|
||||
} else {
|
||||
headers_.append(buf, buf+r);
|
||||
if(headers_.size() > 8192) {
|
||||
headers_.append(buf, buf + r);
|
||||
if (headers_.size() > 8192) {
|
||||
std::cerr << "Too large http header" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(headers_.find("\r\n\r\n") != std::string::npos) {
|
||||
if (headers_.find("\r\n\r\n") != std::string::npos) {
|
||||
std::string::size_type keyhdstart;
|
||||
if(headers_.find("Upgrade: websocket\r\n") == std::string::npos ||
|
||||
headers_.find("Connection: Upgrade\r\n") == std::string::npos ||
|
||||
(keyhdstart = headers_.find("Sec-WebSocket-Key: ")) ==
|
||||
std::string::npos) {
|
||||
if (headers_.find("Upgrade: websocket\r\n") == std::string::npos ||
|
||||
headers_.find("Connection: Upgrade\r\n") == std::string::npos ||
|
||||
(keyhdstart = headers_.find("Sec-WebSocket-Key: ")) ==
|
||||
std::string::npos) {
|
||||
std::cerr << "http_upgrade: missing required headers" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
keyhdstart += 19;
|
||||
std::string::size_type keyhdend = headers_.find("\r\n", keyhdstart);
|
||||
client_key = headers_.substr(keyhdstart, keyhdend-keyhdstart);
|
||||
client_key = headers_.substr(keyhdstart, keyhdend - keyhdstart);
|
||||
accept_key_ = create_acceptkey(client_key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual int on_write_event()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual bool want_read()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual bool want_write()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
virtual bool finish()
|
||||
{
|
||||
return !accept_key_.empty();
|
||||
}
|
||||
virtual EventHandler* next()
|
||||
{
|
||||
if(finish()) {
|
||||
virtual int on_write_event() { return 0; }
|
||||
virtual bool want_read() { return true; }
|
||||
virtual bool want_write() { return false; }
|
||||
virtual int fd() const { return fd_; }
|
||||
virtual bool finish() { return !accept_key_.empty(); }
|
||||
virtual EventHandler *next() {
|
||||
if (finish()) {
|
||||
int fd = fd_;
|
||||
fd_ = -1;
|
||||
return new HttpHandshakeSendHandler(fd, accept_key_);
|
||||
@ -443,6 +380,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
std::string headers_;
|
||||
@ -451,54 +389,35 @@ private:
|
||||
|
||||
class ListenEventHandler : public EventHandler {
|
||||
public:
|
||||
ListenEventHandler(int fd)
|
||||
: fd_(fd), cfd_(-1)
|
||||
{}
|
||||
virtual ~ListenEventHandler()
|
||||
{
|
||||
ListenEventHandler(int fd) : fd_(fd), cfd_(-1) {}
|
||||
virtual ~ListenEventHandler() {
|
||||
close(fd_);
|
||||
close(cfd_);
|
||||
}
|
||||
virtual int on_read_event()
|
||||
{
|
||||
if(cfd_ != -1) {
|
||||
virtual int on_read_event() {
|
||||
if (cfd_ != -1) {
|
||||
close(cfd_);
|
||||
}
|
||||
while((cfd_ = accept(fd_, 0, 0)) == -1 && errno == EINTR);
|
||||
if(cfd_ == -1) {
|
||||
while ((cfd_ = accept(fd_, 0, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (cfd_ == -1) {
|
||||
perror("accept");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual int on_write_event()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual bool want_read()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual bool want_write()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
virtual bool finish()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual EventHandler* next()
|
||||
{
|
||||
if(cfd_ != -1) {
|
||||
virtual int on_write_event() { return 0; }
|
||||
virtual bool want_read() { return true; }
|
||||
virtual bool want_write() { return false; }
|
||||
virtual int fd() const { return fd_; }
|
||||
virtual bool finish() { return false; }
|
||||
virtual EventHandler *next() {
|
||||
if (cfd_ != -1) {
|
||||
int val = 1;
|
||||
int fd = cfd_;
|
||||
cfd_ = -1;
|
||||
if(make_non_block(fd) == -1 ||
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
|
||||
== -1) {
|
||||
if (make_non_block(fd) == -1 ||
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val,
|
||||
(socklen_t)sizeof(val)) == -1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@ -507,20 +426,20 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
int cfd_;
|
||||
};
|
||||
|
||||
int ctl_epollev(int epollfd, int op, EventHandler *handler)
|
||||
{
|
||||
int ctl_epollev(int epollfd, int op, EventHandler *handler) {
|
||||
epoll_event ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
int events = 0;
|
||||
if(handler->want_read()) {
|
||||
if (handler->want_read()) {
|
||||
events |= EPOLLIN;
|
||||
}
|
||||
if(handler->want_write()) {
|
||||
if (handler->want_write()) {
|
||||
events |= EPOLLOUT;
|
||||
}
|
||||
ev.events = events;
|
||||
@ -528,42 +447,41 @@ int ctl_epollev(int epollfd, int op, EventHandler *handler)
|
||||
return epoll_ctl(epollfd, op, handler->fd(), &ev);
|
||||
}
|
||||
|
||||
void reactor(int sfd)
|
||||
{
|
||||
std::set<EventHandler*> handlers;
|
||||
ListenEventHandler* listen_handler = new ListenEventHandler(sfd);
|
||||
void reactor(int sfd) {
|
||||
std::set<EventHandler *> handlers;
|
||||
ListenEventHandler *listen_handler = new ListenEventHandler(sfd);
|
||||
handlers.insert(listen_handler);
|
||||
int epollfd = epoll_create(16);
|
||||
if(epollfd == -1) {
|
||||
if (epollfd == -1) {
|
||||
perror("epoll_create");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(ctl_epollev(epollfd, EPOLL_CTL_ADD, listen_handler) == -1) {
|
||||
if (ctl_epollev(epollfd, EPOLL_CTL_ADD, listen_handler) == -1) {
|
||||
perror("epoll_ctl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
static const size_t MAX_EVENTS = 64;
|
||||
epoll_event events[MAX_EVENTS];
|
||||
while(1) {
|
||||
while (1) {
|
||||
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
|
||||
if(nfds == -1) {
|
||||
if (nfds == -1) {
|
||||
perror("epoll_wait");
|
||||
return;
|
||||
}
|
||||
for(int n = 0; n < nfds; ++n) {
|
||||
EventHandler* eh = (EventHandler*)events[n].data.ptr;
|
||||
if(((events[n].events & EPOLLIN) && eh->on_read_event() == -1) ||
|
||||
((events[n].events & EPOLLOUT) && eh->on_write_event() == -1) ||
|
||||
(events[n].events & (EPOLLERR | EPOLLHUP))) {
|
||||
for (int n = 0; n < nfds; ++n) {
|
||||
EventHandler *eh = (EventHandler *)events[n].data.ptr;
|
||||
if (((events[n].events & EPOLLIN) && eh->on_read_event() == -1) ||
|
||||
((events[n].events & EPOLLOUT) && eh->on_write_event() == -1) ||
|
||||
(events[n].events & (EPOLLERR | EPOLLHUP))) {
|
||||
handlers.erase(eh);
|
||||
delete eh;
|
||||
} else {
|
||||
EventHandler* next = eh->next();
|
||||
if(next) {
|
||||
EventHandler *next = eh->next();
|
||||
if (next) {
|
||||
handlers.insert(next);
|
||||
if(ctl_epollev(epollfd, EPOLL_CTL_ADD, next) == -1) {
|
||||
if(errno == EEXIST) {
|
||||
if(ctl_epollev(epollfd, EPOLL_CTL_MOD, next) == -1) {
|
||||
if (ctl_epollev(epollfd, EPOLL_CTL_ADD, next) == -1) {
|
||||
if (errno == EEXIST) {
|
||||
if (ctl_epollev(epollfd, EPOLL_CTL_MOD, next) == -1) {
|
||||
perror("epoll_ctl");
|
||||
delete next;
|
||||
}
|
||||
@ -573,11 +491,11 @@ void reactor(int sfd)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(eh->finish()) {
|
||||
if (eh->finish()) {
|
||||
handlers.erase(eh);
|
||||
delete eh;
|
||||
} else {
|
||||
if(ctl_epollev(epollfd, EPOLL_CTL_MOD, eh) == -1) {
|
||||
if (ctl_epollev(epollfd, EPOLL_CTL_MOD, eh) == -1) {
|
||||
perror("epoll_ctl");
|
||||
}
|
||||
}
|
||||
@ -586,9 +504,8 @@ void reactor(int sfd)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc < 2) {
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " PORT" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -597,7 +514,7 @@ int main(int argc, char **argv)
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &act, 0);
|
||||
int sfd = create_listen_socket(argv[1]);
|
||||
if(sfd == -1) {
|
||||
if (sfd == -1) {
|
||||
std::cerr << "Failed to create server socket" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
263
deps/wslay/examples/fork-echoserv.c
vendored
263
deps/wslay/examples/fork-echoserv.c
vendored
@ -60,8 +60,7 @@
|
||||
* Create server socket, listen on *service*. This function returns
|
||||
* file descriptor of server socket if it succeeds, or returns -1.
|
||||
*/
|
||||
int create_listen_socket(const char *service)
|
||||
{
|
||||
static int create_listen_socket(const char *service) {
|
||||
struct addrinfo hints, *res, *rp;
|
||||
int sfd = -1;
|
||||
int r;
|
||||
@ -70,27 +69,27 @@ int create_listen_socket(const char *service)
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
||||
r = getaddrinfo(0, service, &hints, &res);
|
||||
if(r != 0) {
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s", gai_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
for(rp = res; rp; rp = rp->ai_next) {
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
int val = 1;
|
||||
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if(sfd == -1) {
|
||||
if (sfd == -1) {
|
||||
continue;
|
||||
}
|
||||
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
(socklen_t)sizeof(val)) == -1) {
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
(socklen_t)sizeof(val)) == -1) {
|
||||
continue;
|
||||
}
|
||||
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||
break;
|
||||
}
|
||||
close(sfd);
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
if(listen(sfd, 16) == -1) {
|
||||
if (listen(sfd, 16) == -1) {
|
||||
perror("listen");
|
||||
close(sfd);
|
||||
return -1;
|
||||
@ -102,16 +101,17 @@ int create_listen_socket(const char *service)
|
||||
* Makes file descriptor *fd* non-blocking mode.
|
||||
* This function returns 0, or returns -1.
|
||||
*/
|
||||
int make_non_block(int fd)
|
||||
{
|
||||
static int make_non_block(int fd) {
|
||||
int flags, r;
|
||||
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
|
||||
if(flags == -1) {
|
||||
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (flags == -1) {
|
||||
perror("fcntl");
|
||||
return -1;
|
||||
}
|
||||
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("fcntl");
|
||||
return -1;
|
||||
}
|
||||
@ -122,8 +122,7 @@ int make_non_block(int fd)
|
||||
* Calculates SHA-1 hash of *src*. The size of *src* is *src_length* bytes.
|
||||
* *dst* must be at least SHA1_DIGEST_SIZE.
|
||||
*/
|
||||
void sha1(uint8_t *dst, const uint8_t *src, size_t src_length)
|
||||
{
|
||||
static void sha1(uint8_t *dst, const uint8_t *src, size_t src_length) {
|
||||
struct sha1_ctx ctx;
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, src_length, src);
|
||||
@ -135,11 +134,10 @@ void sha1(uint8_t *dst, const uint8_t *src, size_t src_length)
|
||||
* The size of *src* is *src_length*.
|
||||
* *dst* must be at least BASE64_ENCODE_RAW_LENGTH(src_length).
|
||||
*/
|
||||
void base64(uint8_t *dst, const uint8_t *src, size_t src_length)
|
||||
{
|
||||
static void base64(uint8_t *dst, const uint8_t *src, size_t src_length) {
|
||||
struct base64_encode_ctx ctx;
|
||||
base64_encode_init(&ctx);
|
||||
base64_encode_raw(dst, src_length, src);
|
||||
base64_encode_raw((char *)dst, src_length, src);
|
||||
}
|
||||
|
||||
#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
@ -150,13 +148,12 @@ void base64(uint8_t *dst, const uint8_t *src, size_t src_length)
|
||||
* client's handshake and it must be length of 24.
|
||||
* *dst* must be at least BASE64_ENCODE_RAW_LENGTH(20)+1.
|
||||
*/
|
||||
void create_accept_key(char *dst, const char *client_key)
|
||||
{
|
||||
static void create_accept_key(char *dst, const char *client_key) {
|
||||
uint8_t sha1buf[20], key_src[60];
|
||||
memcpy(key_src, client_key, 24);
|
||||
memcpy(key_src+24, WS_GUID, 36);
|
||||
memcpy(key_src + 24, WS_GUID, 36);
|
||||
sha1(sha1buf, key_src, sizeof(key_src));
|
||||
base64((uint8_t*)dst, sha1buf, 20);
|
||||
base64((uint8_t *)dst, sha1buf, 20);
|
||||
dst[BASE64_ENCODE_RAW_LENGTH(20)] = '\0';
|
||||
}
|
||||
|
||||
@ -166,69 +163,59 @@ void create_accept_key(char *dst, const char *client_key)
|
||||
* If the caller is looking for a specific value, we return a pointer to the
|
||||
* start of that value, else we simply return the start of values list.
|
||||
*/
|
||||
static char*
|
||||
http_header_find_field_value(char *header, char *field_name, char *value)
|
||||
{
|
||||
char *header_end,
|
||||
*field_start,
|
||||
*field_end,
|
||||
*next_crlf,
|
||||
*value_start;
|
||||
static const char *http_header_find_field_value(const char *header,
|
||||
const char *field_name,
|
||||
const char *value) {
|
||||
const char *header_end, *field_start, *field_end, *next_crlf, *value_start;
|
||||
int field_name_len;
|
||||
|
||||
/* Pointer to the last character in the header */
|
||||
header_end = header + strlen(header) - 1;
|
||||
|
||||
field_name_len = strlen(field_name);
|
||||
field_name_len = (int)strlen(field_name);
|
||||
|
||||
field_start = header;
|
||||
|
||||
do{
|
||||
field_start = strstr(field_start+1, field_name);
|
||||
do {
|
||||
field_start = strstr(field_start + 1, field_name);
|
||||
|
||||
field_end = field_start + field_name_len - 1;
|
||||
|
||||
if(field_start != NULL
|
||||
&& field_start - header >= 2
|
||||
&& field_start[-2] == '\r'
|
||||
&& field_start[-1] == '\n'
|
||||
&& header_end - field_end >= 1
|
||||
&& field_end[1] == ':')
|
||||
{
|
||||
if (field_start != NULL && field_start - header >= 2 &&
|
||||
field_start[-2] == '\r' && field_start[-1] == '\n' &&
|
||||
header_end - field_end >= 1 && field_end[1] == ':') {
|
||||
break; /* Found the field */
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
continue; /* This is not the one; keep looking. */
|
||||
}
|
||||
} while(field_start != NULL);
|
||||
} while (field_start != NULL);
|
||||
|
||||
if(field_start == NULL)
|
||||
if (field_start == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Find the field terminator */
|
||||
next_crlf = strstr(field_start, "\r\n");
|
||||
|
||||
/* A field is expected to end with \r\n */
|
||||
if(next_crlf == NULL)
|
||||
if (next_crlf == NULL)
|
||||
return NULL; /* Malformed HTTP header! */
|
||||
|
||||
/* If not looking for a value, then return a pointer to the start of values string */
|
||||
if(value == NULL)
|
||||
return field_end+2;
|
||||
if (value == NULL)
|
||||
return field_end + 2;
|
||||
|
||||
value_start = strstr(field_start, value);
|
||||
|
||||
/* Value not found */
|
||||
if(value_start == NULL)
|
||||
if (value_start == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Found the value we're looking for */
|
||||
if(value_start > next_crlf)
|
||||
if (value_start > next_crlf)
|
||||
return NULL; /* ... but after the CRLF terminator of the field. */
|
||||
|
||||
/* The value we found should be properly delineated from the other tokens */
|
||||
if(isalnum(value_start[-1]) || isalnum(value_start[strlen(value)]))
|
||||
if (isalnum(value_start[-1]) || isalnum(value_start[strlen(value)]))
|
||||
return NULL;
|
||||
|
||||
return value_start;
|
||||
@ -239,48 +226,53 @@ http_header_find_field_value(char *header, char *field_name, char *value)
|
||||
* connection to the client. This function returns 0 if it succeeds,
|
||||
* or returns -1.
|
||||
*/
|
||||
int http_handshake(int fd)
|
||||
{
|
||||
static int http_handshake(int fd) {
|
||||
/*
|
||||
* Note: The implementation of HTTP handshake in this function is
|
||||
* written for just a example of how to use of wslay library and is
|
||||
* not meant to be used in production code. In practice, you need
|
||||
* to do more strict verification of the client's handshake.
|
||||
*/
|
||||
char header[16384], accept_key[29], *keyhdstart, *keyhdend, res_header[256];
|
||||
char header[16384], accept_key[29], res_header[256];
|
||||
const char *keyhdstart, *keyhdend;
|
||||
size_t header_length = 0, res_header_sent = 0, res_header_length;
|
||||
ssize_t r;
|
||||
while(1) {
|
||||
while((r = read(fd, header+header_length,
|
||||
sizeof(header)-header_length)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while (1) {
|
||||
while ((r = read(fd, header + header_length,
|
||||
sizeof(header) - header_length)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("read");
|
||||
return -1;
|
||||
} else if(r == 0) {
|
||||
} else if (r == 0) {
|
||||
fprintf(stderr, "HTTP Handshake: Got EOF");
|
||||
return -1;
|
||||
} else {
|
||||
header_length += r;
|
||||
if(header_length >= 4 &&
|
||||
memcmp(header+header_length-4, "\r\n\r\n", 4) == 0) {
|
||||
header_length += (size_t)r;
|
||||
if (header_length >= 4 &&
|
||||
memcmp(header + header_length - 4, "\r\n\r\n", 4) == 0) {
|
||||
break;
|
||||
} else if(header_length == sizeof(header)) {
|
||||
} else if (header_length == sizeof(header)) {
|
||||
fprintf(stderr, "HTTP Handshake: Too large HTTP headers");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
|
||||
http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
|
||||
(keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key", NULL)) == NULL) {
|
||||
if (http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
|
||||
http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
|
||||
(keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key",
|
||||
NULL)) == NULL) {
|
||||
fprintf(stderr, "HTTP Handshake: Missing required header fields");
|
||||
return -1;
|
||||
}
|
||||
for(; *keyhdstart == ' '; ++keyhdstart);
|
||||
for (; *keyhdstart == ' '; ++keyhdstart)
|
||||
;
|
||||
keyhdend = keyhdstart;
|
||||
for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);
|
||||
if(keyhdend-keyhdstart != 24) {
|
||||
for (; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend)
|
||||
;
|
||||
if (keyhdend - keyhdstart != 24) {
|
||||
printf("%s\n", keyhdstart);
|
||||
fprintf(stderr, "HTTP Handshake: Invalid value in Sec-WebSocket-Key");
|
||||
return -1;
|
||||
@ -291,17 +283,19 @@ int http_handshake(int fd)
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: %s\r\n"
|
||||
"\r\n", accept_key);
|
||||
"\r\n",
|
||||
accept_key);
|
||||
res_header_length = strlen(res_header);
|
||||
while(res_header_sent < res_header_length) {
|
||||
while((r = write(fd, res_header+res_header_sent,
|
||||
res_header_length-res_header_sent)) == -1 &&
|
||||
errno == EINTR);
|
||||
if(r == -1) {
|
||||
while (res_header_sent < res_header_length) {
|
||||
while ((r = write(fd, res_header + res_header_sent,
|
||||
res_header_length - res_header_sent)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("write");
|
||||
return -1;
|
||||
} else {
|
||||
res_header_sent += r;
|
||||
res_header_sent += (size_t)r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -315,21 +309,20 @@ struct Session {
|
||||
int fd;
|
||||
};
|
||||
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
struct Session *session = (struct Session*)user_data;
|
||||
static ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
|
||||
size_t len, int flags, void *user_data) {
|
||||
struct Session *session = (struct Session *)user_data;
|
||||
ssize_t r;
|
||||
int sflags = 0;
|
||||
#ifdef MSG_MORE
|
||||
if(flags & WSLAY_MSG_MORE) {
|
||||
if (flags & WSLAY_MSG_MORE) {
|
||||
sflags |= MSG_MORE;
|
||||
}
|
||||
#endif // MSG_MORE
|
||||
while((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
while ((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
@ -338,19 +331,20 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
struct Session *session = (struct Session*)user_data;
|
||||
static ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf,
|
||||
size_t len, int flags, void *user_data) {
|
||||
struct Session *session = (struct Session *)user_data;
|
||||
ssize_t r;
|
||||
while((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
(void)flags;
|
||||
while ((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
}
|
||||
} else if(r == 0) {
|
||||
} else if (r == 0) {
|
||||
/* Unexpected EOF is also treated as an error */
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
r = -1;
|
||||
@ -358,15 +352,13 @@ ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
|
||||
return r;
|
||||
}
|
||||
|
||||
void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
static void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data) {
|
||||
(void)user_data;
|
||||
/* Echo back non-control message */
|
||||
if(!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {
|
||||
arg->opcode, arg->msg, arg->msg_length
|
||||
};
|
||||
if (!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
|
||||
wslay_event_queue_msg(ctx, &msgarg);
|
||||
}
|
||||
}
|
||||
@ -377,31 +369,24 @@ void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
* error occurs. *fd* is the file descriptor of the connection to the
|
||||
* client. This function returns 0 if it succeeds, or returns 0.
|
||||
*/
|
||||
int communicate(int fd)
|
||||
{
|
||||
static int communicate(int fd) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks = {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
on_msg_recv_callback
|
||||
};
|
||||
struct Session session = { fd };
|
||||
recv_callback, send_callback, NULL, NULL, NULL,
|
||||
NULL, on_msg_recv_callback};
|
||||
struct Session session = {fd};
|
||||
int val = 1;
|
||||
struct pollfd event;
|
||||
int res = 0;
|
||||
|
||||
if(http_handshake(fd) == -1) {
|
||||
if (http_handshake(fd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if(make_non_block(fd) == -1) {
|
||||
if (make_non_block(fd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
|
||||
== -1) {
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) ==
|
||||
-1) {
|
||||
perror("setsockopt: TCP_NODELAY");
|
||||
return -1;
|
||||
}
|
||||
@ -413,17 +398,18 @@ int communicate(int fd)
|
||||
* Event loop: basically loop until both wslay_event_want_read(ctx)
|
||||
* and wslay_event_want_write(ctx) return 0.
|
||||
*/
|
||||
while(wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) {
|
||||
while (wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) {
|
||||
int r;
|
||||
while((r = poll(&event, 1, -1)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while ((r = poll(&event, 1, -1)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("poll");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if(((event.revents & POLLIN) && wslay_event_recv(ctx) != 0) ||
|
||||
((event.revents & POLLOUT) && wslay_event_send(ctx) != 0) ||
|
||||
(event.revents & (POLLERR | POLLHUP | POLLNVAL))) {
|
||||
if (((event.revents & POLLIN) && wslay_event_recv(ctx) != 0) ||
|
||||
((event.revents & POLLOUT) && wslay_event_send(ctx) != 0) ||
|
||||
(event.revents & (POLLERR | POLLHUP | POLLNVAL))) {
|
||||
/*
|
||||
* If either wslay_event_recv() or wslay_event_send() return
|
||||
* non-zero value, it means serious error which prevents wslay
|
||||
@ -434,10 +420,10 @@ int communicate(int fd)
|
||||
break;
|
||||
}
|
||||
event.events = 0;
|
||||
if(wslay_event_want_read(ctx)) {
|
||||
if (wslay_event_want_read(ctx)) {
|
||||
event.events |= POLLIN;
|
||||
}
|
||||
if(wslay_event_want_write(ctx)) {
|
||||
if (wslay_event_want_write(ctx)) {
|
||||
event.events |= POLLOUT;
|
||||
}
|
||||
}
|
||||
@ -451,23 +437,23 @@ int communicate(int fd)
|
||||
* process communicates with client. The parent process goes back to
|
||||
* the loop and can accept another client.
|
||||
*/
|
||||
void serve(int sfd)
|
||||
{
|
||||
while(1) {
|
||||
static void __attribute__((noreturn)) serve(int sfd) {
|
||||
while (1) {
|
||||
int fd;
|
||||
while((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
if(fd == -1) {
|
||||
while ((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (fd == -1) {
|
||||
perror("accept");
|
||||
} else {
|
||||
int r = fork();
|
||||
if(r == -1) {
|
||||
if (r == -1) {
|
||||
perror("fork");
|
||||
close(fd);
|
||||
} else if(r == 0) {
|
||||
int r = communicate(fd);
|
||||
} else if (r == 0) {
|
||||
r = communicate(fd);
|
||||
shutdown(fd, SHUT_WR);
|
||||
close(fd);
|
||||
if(r == 0) {
|
||||
if (r == 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
exit(EXIT_FAILURE);
|
||||
@ -477,11 +463,10 @@ void serve(int sfd)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
struct sigaction act;
|
||||
int sfd;
|
||||
if(argc < 2) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -491,7 +476,7 @@ int main(int argc, char **argv)
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
|
||||
sfd = create_listen_socket(argv[1]);
|
||||
if(sfd == -1) {
|
||||
if (sfd == -1) {
|
||||
fprintf(stderr, "Failed to create server socket\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
326
deps/wslay/examples/testclient.cc
vendored
326
deps/wslay/examples/testclient.cc
vendored
@ -52,8 +52,7 @@
|
||||
#include <nettle/sha.h>
|
||||
#include <wslay/wslay.h>
|
||||
|
||||
int connect_to(const char *host, const char *service)
|
||||
{
|
||||
int connect_to(const char *host, const char *service) {
|
||||
struct addrinfo hints;
|
||||
int fd = -1;
|
||||
int r;
|
||||
@ -62,18 +61,19 @@ int connect_to(const char *host, const char *service)
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
struct addrinfo *res;
|
||||
r = getaddrinfo(host, service, &hints, &res);
|
||||
if(r != 0) {
|
||||
if (r != 0) {
|
||||
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
continue;
|
||||
}
|
||||
while((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
|
||||
errno == EINTR);
|
||||
if(r == 0) {
|
||||
while ((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
@ -83,91 +83,77 @@ int connect_to(const char *host, const char *service)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int make_non_block(int fd)
|
||||
{
|
||||
int make_non_block(int fd) {
|
||||
int flags, r;
|
||||
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
|
||||
if(flags == -1) {
|
||||
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string sha1(const std::string& src)
|
||||
{
|
||||
std::string sha1(const std::string &src) {
|
||||
sha1_ctx ctx;
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
|
||||
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t *>(src.c_str()));
|
||||
uint8_t temp[SHA1_DIGEST_SIZE];
|
||||
sha1_digest(&ctx, SHA1_DIGEST_SIZE, temp);
|
||||
std::string res(&temp[0], &temp[SHA1_DIGEST_SIZE]);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string base64(const std::string& src)
|
||||
{
|
||||
std::string base64(const std::string &src) {
|
||||
base64_encode_ctx ctx;
|
||||
base64_encode_init(&ctx);
|
||||
int dstlen = BASE64_ENCODE_RAW_LENGTH(src.size());
|
||||
uint8_t *dst = new uint8_t[dstlen];
|
||||
char *dst = new char[dstlen];
|
||||
base64_encode_raw(dst, src.size(),
|
||||
reinterpret_cast<const uint8_t*>(src.c_str()));
|
||||
reinterpret_cast<const uint8_t *>(src.c_str()));
|
||||
std::string res(&dst[0], &dst[dstlen]);
|
||||
delete [] dst;
|
||||
delete[] dst;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string create_acceptkey(const std::string& clientkey)
|
||||
{
|
||||
std::string s = clientkey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
std::string create_acceptkey(const std::string &clientkey) {
|
||||
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
return base64(sha1(s));
|
||||
}
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
WebSocketClient(int fd, struct wslay_event_callbacks *callbacks,
|
||||
const std::string& body)
|
||||
: fd_(fd),
|
||||
body_(body),
|
||||
body_off_(0),
|
||||
dev_urand_("/dev/urandom")
|
||||
{
|
||||
const std::string &body)
|
||||
: fd_(fd), body_(body), body_off_(0), dev_urand_("/dev/urandom") {
|
||||
wslay_event_context_client_init(&ctx_, callbacks, this);
|
||||
}
|
||||
~WebSocketClient()
|
||||
{
|
||||
~WebSocketClient() {
|
||||
wslay_event_context_free(ctx_);
|
||||
shutdown(fd_, SHUT_WR);
|
||||
close(fd_);
|
||||
}
|
||||
int on_read_event()
|
||||
{
|
||||
return wslay_event_recv(ctx_);
|
||||
}
|
||||
int on_write_event()
|
||||
{
|
||||
return wslay_event_send(ctx_);
|
||||
}
|
||||
ssize_t send_data(const uint8_t *data, size_t len, int flags)
|
||||
{
|
||||
int on_read_event() { return wslay_event_recv(ctx_); }
|
||||
int on_write_event() { return wslay_event_send(ctx_); }
|
||||
ssize_t send_data(const uint8_t *data, size_t len, int flags) {
|
||||
ssize_t r;
|
||||
int sflags = 0;
|
||||
#ifdef MSG_MORE
|
||||
if(flags & WSLAY_MSG_MORE) {
|
||||
if (flags & WSLAY_MSG_MORE) {
|
||||
sflags |= MSG_MORE;
|
||||
}
|
||||
#endif // MSG_MORE
|
||||
while((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR);
|
||||
while ((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
ssize_t feed_body(uint8_t *data, size_t len)
|
||||
{
|
||||
if(body_off_ < body_.size()) {
|
||||
size_t wlen = std::min(len, body_.size()-body_off_);
|
||||
ssize_t feed_body(uint8_t *data, size_t len) {
|
||||
if (body_off_ < body_.size()) {
|
||||
size_t wlen = std::min(len, body_.size() - body_off_);
|
||||
memcpy(data, body_.c_str(), wlen);
|
||||
body_off_ += wlen;
|
||||
return wlen;
|
||||
@ -175,32 +161,22 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ssize_t recv_data(uint8_t *data, size_t len, int flags)
|
||||
{
|
||||
ssize_t recv_data(uint8_t *data, size_t len, int flags) {
|
||||
ssize_t r;
|
||||
while((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR);
|
||||
while ((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
bool want_read()
|
||||
{
|
||||
return wslay_event_want_read(ctx_);
|
||||
bool want_read() { return wslay_event_want_read(ctx_); }
|
||||
bool want_write() { return wslay_event_want_write(ctx_); }
|
||||
int fd() const { return fd_; }
|
||||
void get_random(uint8_t *buf, size_t len) {
|
||||
dev_urand_.read((char *)buf, len);
|
||||
}
|
||||
bool want_write()
|
||||
{
|
||||
return wslay_event_want_write(ctx_);
|
||||
}
|
||||
int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
void get_random(uint8_t *buf, size_t len)
|
||||
{
|
||||
dev_urand_.read((char*)buf, len);
|
||||
}
|
||||
void set_callbacks(const struct wslay_event_callbacks *callbacks)
|
||||
{
|
||||
void set_callbacks(const struct wslay_event_callbacks *callbacks) {
|
||||
wslay_event_config_set_callbacks(ctx_, callbacks);
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
wslay_event_context_ptr ctx_;
|
||||
@ -209,14 +185,12 @@ private:
|
||||
std::fstream dev_urand_;
|
||||
};
|
||||
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
WebSocketClient *ws = (WebSocketClient*)user_data;
|
||||
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
|
||||
size_t len, int flags, void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
ssize_t r = ws->send_data(data, len, flags);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
@ -226,71 +200,63 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
|
||||
}
|
||||
|
||||
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
WebSocketClient *ws = (WebSocketClient*)user_data;
|
||||
int flags, void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
ssize_t r = ws->recv_data(data, len, flags);
|
||||
if(r == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
|
||||
} else {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
}
|
||||
} else if(r == 0) {
|
||||
} else if (r == 0) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
r = -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t feed_body_callback
|
||||
(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
WebSocketClient *ws = (WebSocketClient*)user_data;
|
||||
ssize_t feed_body_callback(wslay_event_context_ptr ctx, uint8_t *data,
|
||||
size_t len, int flags, void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
return ws->feed_body(data, len);
|
||||
}
|
||||
|
||||
int genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
WebSocketClient *ws = (WebSocketClient*)user_data;
|
||||
void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
ws->get_random(buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
if(!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {
|
||||
arg->opcode, arg->msg, arg->msg_length
|
||||
};
|
||||
void *user_data) {
|
||||
if (!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
|
||||
wslay_event_queue_msg(ctx, &msgarg);
|
||||
}
|
||||
}
|
||||
|
||||
std::string casecntjson;
|
||||
|
||||
void get_casecnt_on_msg_recv_callback
|
||||
(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
if(arg->opcode == WSLAY_TEXT_FRAME) {
|
||||
casecntjson.assign(arg->msg, arg->msg+arg->msg_length);
|
||||
void get_casecnt_on_msg_recv_callback(
|
||||
wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data) {
|
||||
if (arg->opcode == WSLAY_TEXT_FRAME) {
|
||||
casecntjson.assign(arg->msg, arg->msg + arg->msg_length);
|
||||
}
|
||||
}
|
||||
|
||||
int send_http_handshake(int fd, const std::string& reqheader)
|
||||
{
|
||||
int send_http_handshake(int fd, const std::string &reqheader) {
|
||||
size_t off = 0;
|
||||
while(off < reqheader.size()) {
|
||||
while (off < reqheader.size()) {
|
||||
ssize_t r;
|
||||
size_t len = reqheader.size()-off;
|
||||
while((r = write(fd, reqheader.c_str()+off, len)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
size_t len = reqheader.size() - off;
|
||||
while ((r = write(fd, reqheader.c_str() + off, len)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
@ -299,20 +265,20 @@ int send_http_handshake(int fd, const std::string& reqheader)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recv_http_handshake(int fd, std::string& resheader)
|
||||
{
|
||||
int recv_http_handshake(int fd, std::string &resheader) {
|
||||
char buf[4096];
|
||||
while(1) {
|
||||
while (1) {
|
||||
ssize_t r;
|
||||
while((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR);
|
||||
if(r <= 0) {
|
||||
while ((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r <= 0) {
|
||||
return -1;
|
||||
}
|
||||
resheader.append(buf, buf+r);
|
||||
if(resheader.find("\r\n\r\n") != std::string::npos) {
|
||||
resheader.append(buf, buf + r);
|
||||
if (resheader.find("\r\n\r\n") != std::string::npos) {
|
||||
break;
|
||||
}
|
||||
if(resheader.size() > 8192) {
|
||||
if (resheader.size() > 8192) {
|
||||
std::cerr << "Too big response header" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
@ -320,17 +286,15 @@ int recv_http_handshake(int fd, std::string& resheader)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string get_random16()
|
||||
{
|
||||
std::string get_random16() {
|
||||
char buf[16];
|
||||
std::fstream f("/dev/urandom");
|
||||
f.read(buf, 16);
|
||||
return std::string(buf, buf+16);
|
||||
return std::string(buf, buf + 16);
|
||||
}
|
||||
|
||||
int http_handshake(int fd, const char *host, const char *service,
|
||||
const char *path, std::string& body)
|
||||
{
|
||||
const char *path, std::string &body) {
|
||||
char buf[4096];
|
||||
std::string client_key = base64(get_random16());
|
||||
snprintf(buf, sizeof(buf),
|
||||
@ -343,77 +307,75 @@ int http_handshake(int fd, const char *host, const char *service,
|
||||
"\r\n",
|
||||
path, host, service, client_key.c_str());
|
||||
std::string reqheader = buf;
|
||||
if(send_http_handshake(fd, reqheader) == -1) {
|
||||
if (send_http_handshake(fd, reqheader) == -1) {
|
||||
return -1;
|
||||
}
|
||||
std::string resheader;
|
||||
if(recv_http_handshake(fd, resheader) == -1) {
|
||||
if (recv_http_handshake(fd, resheader) == -1) {
|
||||
return -1;
|
||||
}
|
||||
std::string::size_type keyhdstart;
|
||||
if((keyhdstart = resheader.find("Sec-WebSocket-Accept: ")) ==
|
||||
std::string::npos) {
|
||||
if ((keyhdstart = resheader.find("Sec-WebSocket-Accept: ")) ==
|
||||
std::string::npos) {
|
||||
std::cerr << "http_upgrade: missing required headers" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
keyhdstart += 22;
|
||||
std::string::size_type keyhdend = resheader.find("\r\n", keyhdstart);
|
||||
std::string accept_key = resheader.substr(keyhdstart, keyhdend-keyhdstart);
|
||||
if(accept_key == create_acceptkey(client_key)) {
|
||||
body = resheader.substr(resheader.find("\r\n\r\n")+4);
|
||||
std::string accept_key = resheader.substr(keyhdstart, keyhdend - keyhdstart);
|
||||
if (accept_key == create_acceptkey(client_key)) {
|
||||
body = resheader.substr(resheader.find("\r\n\r\n") + 4);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ctl_epollev(int epollfd, int op, WebSocketClient& ws)
|
||||
{
|
||||
void ctl_epollev(int epollfd, int op, WebSocketClient &ws) {
|
||||
epoll_event ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
if(ws.want_read()) {
|
||||
if (ws.want_read()) {
|
||||
ev.events |= EPOLLIN;
|
||||
}
|
||||
if(ws.want_write()) {
|
||||
if (ws.want_write()) {
|
||||
ev.events |= EPOLLOUT;
|
||||
}
|
||||
if(epoll_ctl(epollfd, op, ws.fd(), &ev) == -1) {
|
||||
if (epoll_ctl(epollfd, op, ws.fd(), &ev) == -1) {
|
||||
perror("epoll_ctl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int communicate(const char *host, const char *service, const char *path,
|
||||
const struct wslay_event_callbacks *callbacks)
|
||||
{
|
||||
const struct wslay_event_callbacks *callbacks) {
|
||||
struct wslay_event_callbacks cb = *callbacks;
|
||||
cb.recv_callback = feed_body_callback;
|
||||
int fd = connect_to(host, service);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
std::cerr << "Could not connect to the host" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::string body;
|
||||
if(http_handshake(fd, host, service, path, body) == -1) {
|
||||
if (http_handshake(fd, host, service, path, body) == -1) {
|
||||
std::cerr << "Failed handshake" << std::endl;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
make_non_block(fd);
|
||||
int val = 1;
|
||||
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
|
||||
== -1) {
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) ==
|
||||
-1) {
|
||||
perror("setsockopt: TCP_NODELAY");
|
||||
return -1;
|
||||
}
|
||||
WebSocketClient ws(fd, &cb, body);
|
||||
if(ws.on_read_event() == -1) {
|
||||
if (ws.on_read_event() == -1) {
|
||||
return -1;
|
||||
}
|
||||
cb.recv_callback = callbacks->recv_callback;
|
||||
ws.set_callbacks(&cb);
|
||||
int epollfd = epoll_create(1);
|
||||
if(epollfd == -1) {
|
||||
if (epollfd == -1) {
|
||||
perror("epoll_create");
|
||||
return -1;
|
||||
}
|
||||
@ -421,20 +383,20 @@ int communicate(const char *host, const char *service, const char *path,
|
||||
static const size_t MAX_EVENTS = 1;
|
||||
epoll_event events[MAX_EVENTS];
|
||||
bool ok = true;
|
||||
while(ws.want_read() || ws.want_write()) {
|
||||
while (ws.want_read() || ws.want_write()) {
|
||||
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
|
||||
if(nfds == -1) {
|
||||
if (nfds == -1) {
|
||||
perror("epoll_wait");
|
||||
return -1;
|
||||
}
|
||||
for(int n = 0; n < nfds; ++n) {
|
||||
if(((events[n].events & EPOLLIN) && ws.on_read_event() != 0) ||
|
||||
((events[n].events & EPOLLOUT) && ws.on_write_event() != 0)) {
|
||||
for (int n = 0; n < nfds; ++n) {
|
||||
if (((events[n].events & EPOLLIN) && ws.on_read_event() != 0) ||
|
||||
((events[n].events & EPOLLOUT) && ws.on_write_event() != 0)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
ctl_epollev(epollfd, EPOLL_CTL_MOD, ws);
|
||||
@ -442,61 +404,53 @@ int communicate(const char *host, const char *service, const char *path,
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
int get_casecnt(const char *host, const char *service)
|
||||
{
|
||||
int get_casecnt(const char *host, const char *service) {
|
||||
struct wslay_event_callbacks callbacks = {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
get_casecnt_on_msg_recv_callback
|
||||
};
|
||||
if(communicate(host, service, "/getCaseCount", &callbacks) == -1) {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
get_casecnt_on_msg_recv_callback};
|
||||
if (communicate(host, service, "/getCaseCount", &callbacks) == -1) {
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
int casecnt = strtol(casecntjson.c_str(), 0, 10);
|
||||
if(errno == ERANGE) {
|
||||
if (errno == ERANGE) {
|
||||
return -1;
|
||||
} else {
|
||||
return casecnt;
|
||||
}
|
||||
}
|
||||
|
||||
int run_testcase(const char *host, const char *service, int casenum)
|
||||
{
|
||||
int run_testcase(const char *host, const char *service, int casenum) {
|
||||
struct wslay_event_callbacks callbacks = {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_callback
|
||||
};
|
||||
recv_callback,
|
||||
send_callback,
|
||||
genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_callback};
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "/runCase?case=%d&agent=wslay", casenum);
|
||||
return communicate(host, service, buf, &callbacks);
|
||||
}
|
||||
int update_reports(const char *host, const char *service)
|
||||
{
|
||||
int update_reports(const char *host, const char *service) {
|
||||
struct wslay_event_callbacks callbacks = {
|
||||
recv_callback,
|
||||
send_callback,
|
||||
genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
NULL, /* on_msg_recv_callback */
|
||||
recv_callback, send_callback, genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
NULL, /* on_msg_recv_callback */
|
||||
};
|
||||
return communicate(host, service, "/updateReports?&agent=wslay", &callbacks);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc < 3) {
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " HOST SERV" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -507,17 +461,17 @@ int main(int argc, char **argv)
|
||||
const char *host = argv[1];
|
||||
const char *service = argv[2];
|
||||
int casecnt = get_casecnt(host, service);
|
||||
if(casecnt == -1) {
|
||||
if (casecnt == -1) {
|
||||
std::cerr << "Failed to get case count." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for(int i = 1; i <= casecnt; ++i) {
|
||||
for (int i = 1; i <= casecnt; ++i) {
|
||||
std::cout << "Running test case " << i << std::endl;
|
||||
if(run_testcase(host, service, i) == -1) {
|
||||
if (run_testcase(host, service, i) == -1) {
|
||||
std::cout << "Detected error during test" << std::endl;
|
||||
}
|
||||
}
|
||||
if(update_reports(host, service) == -1) {
|
||||
if (update_reports(host, service) == -1) {
|
||||
std::cerr << "Failed to update reports." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
2
deps/wslay/lib/Makefile.am
vendored
2
deps/wslay/lib/Makefile.am
vendored
@ -33,7 +33,7 @@ OBJECTS = wslay_frame.c wslay_event.c\
|
||||
wslay_queue.c wslay_net.c
|
||||
|
||||
HFILES = wslay_frame.h wslay_event.h\
|
||||
wslay_queue.h wslay_net.h
|
||||
wslay_queue.h wslay_net.h wslay_macro.h
|
||||
|
||||
libwslay_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||
libwslay_la_LDFLAGS = -no-undefined \
|
||||
|
141
deps/wslay/lib/includes/wslay/wslay.h
vendored
141
deps/wslay/lib/includes/wslay/wslay.h
vendored
@ -25,7 +25,7 @@
|
||||
#ifndef WSLAY_H
|
||||
#define WSLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -33,7 +33,6 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/*
|
||||
* wslay/wslayver.h is generated from wslay/wslayver.h.in by
|
||||
* configure. The projects which do not use autotools can set
|
||||
@ -149,10 +148,10 @@ enum wslay_opcode {
|
||||
* 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_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)
|
||||
@ -166,7 +165,7 @@ struct wslay_frame_iocb {
|
||||
* RFC6455 requires 0 unless extensions are negotiated.
|
||||
*/
|
||||
uint8_t rsv;
|
||||
/* 4 bit opcode */
|
||||
/* 4 bit opcode */
|
||||
uint8_t opcode;
|
||||
/* payload length [0, 2**63-1] */
|
||||
uint64_t payload_length;
|
||||
@ -222,6 +221,33 @@ void wslay_frame_context_free(wslay_frame_context_ptr ctx);
|
||||
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
||||
struct wslay_frame_iocb *iocb);
|
||||
|
||||
/*
|
||||
* Write WebSocket frame specified in iocb to buf of length
|
||||
* buflen. 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. Unlike
|
||||
* wslay_frame_send, this function does not call send_callback
|
||||
* function. This function calls gen_mask_callback function if it
|
||||
* needs new mask key. This function returns the number of bytes
|
||||
* written to a buffer. Unlike wslay_frame_send, it includes the
|
||||
* number of header bytes. Instead, the number of payload bytes
|
||||
* written is assigned to *pwpayloadlen if this function succeeds. If
|
||||
* there is not enough space left in a buffer, it returns 0. 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_write(wslay_frame_context_ptr ctx,
|
||||
struct wslay_frame_iocb *iocb, uint8_t *buf,
|
||||
size_t buflen, size_t *pwpayloadlen);
|
||||
|
||||
/*
|
||||
* Receives WebSocket frame and stores it in iocb. This function
|
||||
* returns the number of payload bytes received. This does not
|
||||
@ -270,9 +296,9 @@ struct wslay_event_on_msg_recv_arg {
|
||||
* 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);
|
||||
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. */
|
||||
@ -290,9 +316,9 @@ struct wslay_event_on_frame_recv_start_arg {
|
||||
* 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);
|
||||
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 */
|
||||
@ -305,16 +331,16 @@ struct wslay_event_on_frame_recv_chunk_arg {
|
||||
* 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);
|
||||
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);
|
||||
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
|
||||
@ -388,9 +414,9 @@ struct wslay_event_callbacks {
|
||||
* 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);
|
||||
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
|
||||
@ -403,9 +429,9 @@ int wslay_event_context_server_init
|
||||
* 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);
|
||||
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.
|
||||
@ -456,8 +482,8 @@ void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
|
||||
* 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);
|
||||
void wslay_event_config_set_callbacks(
|
||||
wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
|
||||
|
||||
/*
|
||||
* Receives messages from peer. When receiving
|
||||
@ -532,6 +558,50 @@ int wslay_event_recv(wslay_event_context_ptr ctx);
|
||||
*/
|
||||
int wslay_event_send(wslay_event_context_ptr ctx);
|
||||
|
||||
/*
|
||||
* Writes queued messages to a buffer. Unlike wslay_event_send(), this
|
||||
* function writes messages into the given buffer. It does not use
|
||||
* wslay_event_send_callback function. Single call of
|
||||
* wslay_event_write() writes multiple messages until there is not
|
||||
* enough space left in a buffer.
|
||||
*
|
||||
* If ctx is initialized for WebSocket client use, wslay_event_write()
|
||||
* uses wslay_event_genmask_callback to get new mask key.
|
||||
*
|
||||
* buf is a pointer to buffer and its capacity is given in buflen. It
|
||||
* should have at least 14 bytes.
|
||||
*
|
||||
* When a message queued using wslay_event_queue_fragmented_msg() is
|
||||
* sent, wslay_event_write() 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_write() returns the number of bytes written to a buffer
|
||||
* 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_write() and must close WebSocket
|
||||
* connection.
|
||||
*/
|
||||
ssize_t wslay_event_write(wslay_event_context_ptr ctx, uint8_t *buf,
|
||||
size_t buflen);
|
||||
|
||||
struct wslay_event_msg {
|
||||
uint8_t opcode;
|
||||
const uint8_t *msg;
|
||||
@ -588,10 +658,9 @@ union wslay_event_msg_source {
|
||||
* 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);
|
||||
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 */
|
||||
@ -625,15 +694,16 @@ struct wslay_event_fragmented_msg {
|
||||
* WSLAY_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int wslay_event_queue_fragmented_msg
|
||||
(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
|
||||
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);
|
||||
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
|
||||
@ -663,8 +733,7 @@ int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
|
||||
* WSLAY_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int wslay_event_queue_close(wslay_event_context_ptr ctx,
|
||||
uint16_t status_code,
|
||||
int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
|
||||
const uint8_t *reason, size_t reason_length);
|
||||
|
||||
/*
|
||||
|
895
deps/wslay/lib/wslay_event.c
vendored
895
deps/wslay/lib/wslay_event.c
vendored
File diff suppressed because it is too large
Load Diff
20
deps/wslay/lib/wslay_event.h
vendored
20
deps/wslay/lib/wslay_event.h
vendored
@ -31,10 +31,10 @@
|
||||
|
||||
#include <wslay/wslay.h>
|
||||
|
||||
struct wslay_stack;
|
||||
struct wslay_queue;
|
||||
#include "wslay_queue.h"
|
||||
|
||||
struct wslay_event_byte_chunk {
|
||||
struct wslay_queue_entry qe;
|
||||
uint8_t *data;
|
||||
size_t data_length;
|
||||
};
|
||||
@ -44,16 +44,14 @@ struct wslay_event_imsg {
|
||||
uint8_t rsv;
|
||||
uint8_t opcode;
|
||||
uint32_t utf8state;
|
||||
struct wslay_queue *chunks;
|
||||
struct wslay_queue chunks;
|
||||
size_t msg_length;
|
||||
};
|
||||
|
||||
enum wslay_event_msg_type {
|
||||
WSLAY_NON_FRAGMENTED,
|
||||
WSLAY_FRAGMENTED
|
||||
};
|
||||
enum wslay_event_msg_type { WSLAY_NON_FRAGMENTED, WSLAY_FRAGMENTED };
|
||||
|
||||
struct wslay_event_omsg {
|
||||
struct wslay_queue_entry qe;
|
||||
uint8_t fin;
|
||||
uint8_t opcode;
|
||||
uint8_t rsv;
|
||||
@ -77,9 +75,7 @@ enum wslay_event_close_status {
|
||||
WSLAY_CLOSE_SENT = 1 << 2
|
||||
};
|
||||
|
||||
enum wslay_event_config {
|
||||
WSLAY_CONFIG_NO_BUFFERING = 1 << 0
|
||||
};
|
||||
enum wslay_event_config { WSLAY_CONFIG_NO_BUFFERING = 1 << 0 };
|
||||
|
||||
struct wslay_event_context {
|
||||
/* config status, bitwise OR of enum wslay_event_config values*/
|
||||
@ -118,9 +114,9 @@ struct wslay_event_context {
|
||||
is currently sent. */
|
||||
struct wslay_event_omsg *omsg;
|
||||
/* Queue for non-control frames */
|
||||
struct wslay_queue/*<wslay_omsg*>*/ *send_queue;
|
||||
struct wslay_queue /*<wslay_omsg*>*/ send_queue;
|
||||
/* Queue for control frames */
|
||||
struct wslay_queue/*<wslay_omsg*>*/ *send_ctrl_queue;
|
||||
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 */
|
||||
|
306
deps/wslay/lib/wslay_frame.c
vendored
306
deps/wslay/lib/wslay_frame.c
vendored
@ -34,10 +34,9 @@
|
||||
|
||||
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) {
|
||||
void *user_data) {
|
||||
*ctx = malloc(sizeof(struct wslay_frame_context));
|
||||
if (*ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(*ctx, 0, sizeof(struct wslay_frame_context));
|
||||
@ -50,38 +49,35 @@ int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wslay_frame_context_free(wslay_frame_context_ptr ctx)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
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) {
|
||||
struct wslay_frame_iocb *iocb) {
|
||||
if (iocb->data_length > iocb->payload_length) {
|
||||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if(ctx->ostate == PREP_HEADER) {
|
||||
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 |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
|
||||
*hdptr |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
|
||||
/* Suppress stubborn gcc-10 warning */
|
||||
*hdptr |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
|
||||
++hdptr;
|
||||
*hdptr |= (iocb->mask << 7) & 0x80u;
|
||||
if(wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
|
||||
*hdptr |= (uint8_t)((uint8_t)(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;
|
||||
if (iocb->payload_length < 126) {
|
||||
*hdptr |= (uint8_t)iocb->payload_length;
|
||||
++hdptr;
|
||||
} else if(iocb->payload_length < (1 << 16)) {
|
||||
uint16_t len = htons(iocb->payload_length);
|
||||
} else if (iocb->payload_length < (1 << 16)) {
|
||||
uint16_t len = htons((uint16_t)iocb->payload_length);
|
||||
*hdptr |= 126;
|
||||
++hdptr;
|
||||
memcpy(hdptr, &len, 2);
|
||||
hdptr += 2;
|
||||
} else if(iocb->payload_length < (1ull << 63)) {
|
||||
} else if (iocb->payload_length < (1ull << 63)) {
|
||||
uint64_t len = hton64(iocb->payload_length);
|
||||
*hdptr |= 127;
|
||||
++hdptr;
|
||||
@ -91,9 +87,9 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
||||
/* Too large payload length */
|
||||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if(iocb->mask) {
|
||||
if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
|
||||
ctx->user_data) != 0) {
|
||||
if (iocb->mask) {
|
||||
if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
|
||||
0) {
|
||||
return WSLAY_ERR_INVALID_CALLBACK;
|
||||
} else {
|
||||
ctx->omask = 1;
|
||||
@ -107,21 +103,21 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
||||
ctx->opayloadlen = iocb->payload_length;
|
||||
ctx->opayloadoff = 0;
|
||||
}
|
||||
if(ctx->ostate == SEND_HEADER) {
|
||||
ptrdiff_t len = ctx->oheaderlimit-ctx->oheadermark;
|
||||
if (ctx->ostate == SEND_HEADER) {
|
||||
ptrdiff_t len = ctx->oheaderlimit - ctx->oheadermark;
|
||||
ssize_t r;
|
||||
int flags = 0;
|
||||
if(iocb->data_length > 0) {
|
||||
if (iocb->data_length > 0) {
|
||||
flags |= WSLAY_MSG_MORE;
|
||||
};
|
||||
r = ctx->callbacks.send_callback(ctx->oheadermark, len, flags,
|
||||
r = ctx->callbacks.send_callback(ctx->oheadermark, (size_t)len, flags,
|
||||
ctx->user_data);
|
||||
if(r > 0) {
|
||||
if(r > len) {
|
||||
if (r > 0) {
|
||||
if (r > len) {
|
||||
return WSLAY_ERR_INVALID_CALLBACK;
|
||||
} else {
|
||||
ctx->oheadermark += r;
|
||||
if(ctx->oheadermark == ctx->oheaderlimit) {
|
||||
if (ctx->oheadermark == ctx->oheaderlimit) {
|
||||
ctx->ostate = SEND_PAYLOAD;
|
||||
} else {
|
||||
return WSLAY_ERR_WANT_WRITE;
|
||||
@ -131,34 +127,34 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
||||
return WSLAY_ERR_WANT_WRITE;
|
||||
}
|
||||
}
|
||||
if(ctx->ostate == SEND_PAYLOAD) {
|
||||
if (ctx->ostate == SEND_PAYLOAD) {
|
||||
size_t totallen = 0;
|
||||
if(iocb->data_length > 0) {
|
||||
if(ctx->omask) {
|
||||
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;
|
||||
*datalimit = iocb->data + iocb->data_length;
|
||||
while (datamark < datalimit) {
|
||||
size_t datalen = (size_t)(datalimit - datamark);
|
||||
const uint8_t *writelimit =
|
||||
datamark + wslay_min(sizeof(temp), datalen);
|
||||
size_t writelen = (size_t)(writelimit - datamark);
|
||||
ssize_t r;
|
||||
size_t i;
|
||||
for(i = 0; i < writelen; ++i) {
|
||||
temp[i] = datamark[i]^ctx->omaskkey[(ctx->opayloadoff+i)%4];
|
||||
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) {
|
||||
if (r > 0) {
|
||||
if ((size_t)r > writelen) {
|
||||
return WSLAY_ERR_INVALID_CALLBACK;
|
||||
} else {
|
||||
datamark += r;
|
||||
ctx->opayloadoff += r;
|
||||
totallen += r;
|
||||
ctx->opayloadoff += (uint64_t)r;
|
||||
totallen += (size_t)r;
|
||||
}
|
||||
} else {
|
||||
if(totallen > 0) {
|
||||
if (totallen > 0) {
|
||||
break;
|
||||
} else {
|
||||
return WSLAY_ERR_WANT_WRITE;
|
||||
@ -169,44 +165,148 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
||||
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) {
|
||||
if (r > 0) {
|
||||
if ((size_t)r > iocb->data_length) {
|
||||
return WSLAY_ERR_INVALID_CALLBACK;
|
||||
} else {
|
||||
ctx->opayloadoff += r;
|
||||
totallen = r;
|
||||
ctx->opayloadoff += (uint64_t)r;
|
||||
totallen = (size_t)r;
|
||||
}
|
||||
} else {
|
||||
return WSLAY_ERR_WANT_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ctx->opayloadoff == ctx->opayloadlen) {
|
||||
if (ctx->opayloadoff == ctx->opayloadlen) {
|
||||
ctx->ostate = PREP_HEADER;
|
||||
}
|
||||
return totallen;
|
||||
return (ssize_t)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;
|
||||
ssize_t wslay_frame_write(wslay_frame_context_ptr ctx,
|
||||
struct wslay_frame_iocb *iocb, uint8_t *buf,
|
||||
size_t buflen, size_t *pwpayloadlen) {
|
||||
uint8_t *buf_last = buf;
|
||||
size_t i;
|
||||
size_t hdlen;
|
||||
|
||||
*pwpayloadlen = 0;
|
||||
|
||||
if (iocb->data_length > iocb->payload_length) {
|
||||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
switch (ctx->ostate) {
|
||||
case PREP_HEADER:
|
||||
case PREP_HEADER_NOBUF:
|
||||
hdlen = 2;
|
||||
if (iocb->payload_length < 126) {
|
||||
/* nothing to do */
|
||||
} else if (iocb->payload_length < (1 << 16)) {
|
||||
hdlen += 2;
|
||||
} else if (iocb->payload_length < (1ull << 63)) {
|
||||
hdlen += 8;
|
||||
}
|
||||
if (iocb->mask) {
|
||||
hdlen += 4;
|
||||
}
|
||||
|
||||
if (buflen < hdlen) {
|
||||
ctx->ostate = PREP_HEADER_NOBUF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buf_last, 0, hdlen);
|
||||
*buf_last |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
|
||||
*buf_last |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
|
||||
/* Suppress stubborn gcc-10 warning */
|
||||
*buf_last |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
|
||||
++buf_last;
|
||||
*buf_last |= (uint8_t)((uint8_t)(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) {
|
||||
*buf_last |= (uint8_t)iocb->payload_length;
|
||||
++buf_last;
|
||||
} else if (iocb->payload_length < (1 << 16)) {
|
||||
uint16_t len = htons((uint16_t)iocb->payload_length);
|
||||
*buf_last |= 126;
|
||||
++buf_last;
|
||||
memcpy(buf_last, &len, 2);
|
||||
buf_last += 2;
|
||||
} else if (iocb->payload_length < (1ull << 63)) {
|
||||
uint64_t len = hton64(iocb->payload_length);
|
||||
*buf_last |= 127;
|
||||
++buf_last;
|
||||
memcpy(buf_last, &len, 8);
|
||||
buf_last += 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(buf_last, ctx->omaskkey, 4);
|
||||
buf_last += 4;
|
||||
}
|
||||
}
|
||||
ctx->ostate = SEND_PAYLOAD;
|
||||
ctx->opayloadlen = iocb->payload_length;
|
||||
ctx->opayloadoff = 0;
|
||||
|
||||
buflen -= (size_t)(buf_last - buf);
|
||||
/* fall through */
|
||||
case SEND_PAYLOAD:
|
||||
if (iocb->data_length > 0) {
|
||||
size_t writelen = wslay_min(buflen, iocb->data_length);
|
||||
|
||||
if (ctx->omask) {
|
||||
for (i = 0; i < writelen; ++i) {
|
||||
*buf_last++ =
|
||||
iocb->data[i] ^ ctx->omaskkey[(ctx->opayloadoff + i) % 4];
|
||||
}
|
||||
} else {
|
||||
memcpy(buf_last, iocb->data, writelen);
|
||||
buf_last += writelen;
|
||||
}
|
||||
|
||||
ctx->opayloadoff += writelen;
|
||||
*pwpayloadlen = writelen;
|
||||
}
|
||||
|
||||
if (ctx->opayloadoff == ctx->opayloadlen) {
|
||||
ctx->ostate = PREP_HEADER;
|
||||
}
|
||||
|
||||
return buf_last - buf;
|
||||
default:
|
||||
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, (size_t)len);
|
||||
ctx->ibuflimit = ctx->ibuf + len;
|
||||
ctx->ibufmark = ctx->ibuf;
|
||||
}
|
||||
|
||||
static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
|
||||
{
|
||||
static ssize_t wslay_recv(wslay_frame_context_ptr ctx) {
|
||||
ssize_t r;
|
||||
if(ctx->ibufmark != ctx->ibuf) {
|
||||
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) {
|
||||
r = ctx->callbacks.recv_callback(
|
||||
ctx->ibuflimit, (size_t)(ctx->ibuf + sizeof(ctx->ibuf) - ctx->ibuflimit),
|
||||
0, ctx->user_data);
|
||||
if (r > 0) {
|
||||
ctx->ibuflimit += r;
|
||||
} else {
|
||||
r = WSLAY_ERR_WANT_READ;
|
||||
@ -217,17 +317,16 @@ static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
|
||||
#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)
|
||||
{
|
||||
struct wslay_frame_iocb *iocb) {
|
||||
ssize_t r;
|
||||
if(ctx->istate == RECV_HEADER1) {
|
||||
if (ctx->istate == RECV_HEADER1) {
|
||||
uint8_t fin, opcode, rsv, payloadlen;
|
||||
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
if((r = wslay_recv(ctx)) <= 0) {
|
||||
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
if ((r = wslay_recv(ctx)) <= 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
return WSLAY_ERR_WANT_READ;
|
||||
}
|
||||
fin = (ctx->ibufmark[0] >> 7) & 1;
|
||||
@ -240,19 +339,19 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
||||
ctx->imask = (ctx->ibufmark[0] >> 7) & 1;
|
||||
payloadlen = ctx->ibufmark[0] & 0x7fu;
|
||||
++ctx->ibufmark;
|
||||
if(wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
|
||||
if (wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
|
||||
return WSLAY_ERR_PROTO;
|
||||
}
|
||||
if(payloadlen == 126) {
|
||||
if (payloadlen == 126) {
|
||||
ctx->istate = RECV_EXT_PAYLOADLEN;
|
||||
ctx->ireqread = 2;
|
||||
} else if(payloadlen == 127) {
|
||||
} else if (payloadlen == 127) {
|
||||
ctx->istate = RECV_EXT_PAYLOADLEN;
|
||||
ctx->ireqread = 8;
|
||||
} else {
|
||||
ctx->ipayloadlen = payloadlen;
|
||||
ctx->ipayloadoff = 0;
|
||||
if(ctx->imask) {
|
||||
if (ctx->imask) {
|
||||
ctx->istate = RECV_MASKKEY;
|
||||
ctx->ireqread = 4;
|
||||
} else {
|
||||
@ -260,42 +359,41 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ctx->istate == RECV_EXT_PAYLOADLEN) {
|
||||
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
if((r = wslay_recv(ctx)) <= 0) {
|
||||
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) {
|
||||
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);
|
||||
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)) {
|
||||
if (ctx->ireqread == 8) {
|
||||
if (ctx->ipayloadlen < (1 << 16) || ctx->ipayloadlen & (1ull << 63)) {
|
||||
return WSLAY_ERR_PROTO;
|
||||
}
|
||||
} else if(ctx->ipayloadlen < 126) {
|
||||
} else if (ctx->ipayloadlen < 126) {
|
||||
return WSLAY_ERR_PROTO;
|
||||
}
|
||||
if(ctx->imask) {
|
||||
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) {
|
||||
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) {
|
||||
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
|
||||
return WSLAY_ERR_WANT_READ;
|
||||
}
|
||||
}
|
||||
@ -303,25 +401,25 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
||||
ctx->ibufmark += 4;
|
||||
ctx->istate = RECV_PAYLOAD;
|
||||
}
|
||||
if(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) {
|
||||
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) {
|
||||
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;
|
||||
ctx->ipayloadoff += (uint64_t)(readlimit - readmark);
|
||||
}
|
||||
iocb->fin = ctx->iom.fin;
|
||||
iocb->rsv = ctx->iom.rsv;
|
||||
@ -329,12 +427,12 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
||||
iocb->payload_length = ctx->ipayloadlen;
|
||||
iocb->mask = ctx->imask;
|
||||
iocb->data = readmark;
|
||||
iocb->data_length = ctx->ibufmark-readmark;
|
||||
if(ctx->ipayloadlen == ctx->ipayloadoff) {
|
||||
iocb->data_length = (size_t)(ctx->ibufmark - readmark);
|
||||
if (ctx->ipayloadlen == ctx->ipayloadoff) {
|
||||
ctx->istate = RECV_HEADER1;
|
||||
ctx->ireqread = 2;
|
||||
}
|
||||
return iocb->data_length;
|
||||
return (ssize_t)iocb->data_length;
|
||||
}
|
||||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
1
deps/wslay/lib/wslay_frame.h
vendored
1
deps/wslay/lib/wslay_frame.h
vendored
@ -33,6 +33,7 @@
|
||||
|
||||
enum wslay_frame_state {
|
||||
PREP_HEADER,
|
||||
PREP_HEADER_NOBUF,
|
||||
SEND_HEADER,
|
||||
SEND_PAYLOAD,
|
||||
RECV_HEADER1,
|
||||
|
39
deps/wslay/lib/wslay_macro.h
vendored
Normal file
39
deps/wslay/lib/wslay_macro.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Wslay - The WebSocket Library
|
||||
*
|
||||
* Copyright (c) 2020 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_MACRO_H
|
||||
#define WSLAY_MACRO_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <wslay/wslay.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define wslay_struct_of(ptr, type, member) \
|
||||
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
|
||||
|
||||
#endif /* WSLAY_MACRO_H */
|
5
deps/wslay/lib/wslay_net.c
vendored
5
deps/wslay/lib/wslay_net.c
vendored
@ -26,10 +26,9 @@
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
|
||||
uint64_t wslay_byteswap64(uint64_t x)
|
||||
{
|
||||
uint64_t wslay_byteswap64(uint64_t x) {
|
||||
uint64_t u = ntohl(x & 0xffffffffllu);
|
||||
uint64_t l = ntohl(x >> 32);
|
||||
uint64_t l = ntohl((uint32_t)(x >> 32));
|
||||
return (u << 32) | l;
|
||||
}
|
||||
|
||||
|
112
deps/wslay/lib/wslay_queue.c
vendored
112
deps/wslay/lib/wslay_queue.c
vendored
@ -27,91 +27,51 @@
|
||||
#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;
|
||||
#include "wslay_macro.h"
|
||||
|
||||
void wslay_queue_init(struct wslay_queue *queue) {
|
||||
queue->top = NULL;
|
||||
queue->tail = &queue->top;
|
||||
}
|
||||
|
||||
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);
|
||||
void wslay_queue_deinit(struct wslay_queue *queue) { (void)queue; }
|
||||
|
||||
void wslay_queue_push(struct wslay_queue *queue,
|
||||
struct wslay_queue_entry *ent) {
|
||||
ent->next = NULL;
|
||||
*queue->tail = ent;
|
||||
queue->tail = &ent->next;
|
||||
}
|
||||
|
||||
void wslay_queue_push_front(struct wslay_queue *queue,
|
||||
struct wslay_queue_entry *ent) {
|
||||
ent->next = queue->top;
|
||||
queue->top = ent;
|
||||
|
||||
if (ent->next == NULL) {
|
||||
queue->tail = &ent->next;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
void wslay_queue_pop(struct wslay_queue *queue) {
|
||||
assert(queue->top);
|
||||
return queue->top->data;
|
||||
queue->top = queue->top->next;
|
||||
if (queue->top == NULL) {
|
||||
queue->tail = &queue->top;
|
||||
}
|
||||
}
|
||||
|
||||
void* wslay_queue_tail(struct wslay_queue *queue)
|
||||
{
|
||||
assert(queue->tail);
|
||||
return queue->tail->data;
|
||||
struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue) {
|
||||
assert(queue->top);
|
||||
return queue->top;
|
||||
}
|
||||
|
||||
int wslay_queue_empty(struct wslay_queue *queue)
|
||||
{
|
||||
struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue) {
|
||||
assert(queue->top);
|
||||
return wslay_struct_of(queue->tail, struct wslay_queue_entry, next);
|
||||
}
|
||||
|
||||
int wslay_queue_empty(struct wslay_queue *queue) {
|
||||
assert(queue->top || queue->tail == &queue->top);
|
||||
return queue->top == NULL;
|
||||
}
|
||||
|
22
deps/wslay/lib/wslay_queue.h
vendored
22
deps/wslay/lib/wslay_queue.h
vendored
@ -31,23 +31,23 @@
|
||||
|
||||
#include <wslay/wslay.h>
|
||||
|
||||
struct wslay_queue_cell {
|
||||
void *data;
|
||||
struct wslay_queue_cell *next;
|
||||
struct wslay_queue_entry {
|
||||
struct wslay_queue_entry *next;
|
||||
};
|
||||
|
||||
struct wslay_queue {
|
||||
struct wslay_queue_cell *top;
|
||||
struct wslay_queue_cell *tail;
|
||||
struct wslay_queue_entry *top;
|
||||
struct wslay_queue_entry **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_init(struct wslay_queue *queue);
|
||||
void wslay_queue_deinit(struct wslay_queue *queue);
|
||||
void wslay_queue_push(struct wslay_queue *queue, struct wslay_queue_entry *ent);
|
||||
void wslay_queue_push_front(struct wslay_queue *queue,
|
||||
struct wslay_queue_entry *ent);
|
||||
void wslay_queue_pop(struct wslay_queue *queue);
|
||||
void* wslay_queue_top(struct wslay_queue *queue);
|
||||
void* wslay_queue_tail(struct wslay_queue *queue);
|
||||
struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue);
|
||||
struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue);
|
||||
int wslay_queue_empty(struct wslay_queue *queue);
|
||||
|
||||
#endif /* WSLAY_QUEUE_H */
|
||||
|
95
deps/wslay/tests/main.c
vendored
95
deps/wslay/tests/main.c
vendored
@ -30,35 +30,27 @@
|
||||
#include "wslay_event_test.h"
|
||||
#include "wslay_queue_test.h"
|
||||
|
||||
static int init_suite1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int init_suite1(void) { return 0; }
|
||||
|
||||
static int clean_suite1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int clean_suite1(void) { return 0; }
|
||||
|
||||
int main(void) {
|
||||
CU_pSuite pSuite = NULL;
|
||||
unsigned int num_tests_failed;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CU_pSuite pSuite = NULL;
|
||||
unsigned int num_tests_failed;
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
/* add a suite to the registry */
|
||||
pSuite = CU_add_suite("libwslay_TestSuite", init_suite1, clean_suite1);
|
||||
if (NULL == pSuite) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
/* add a suite to the registry */
|
||||
pSuite = CU_add_suite("libwslay_TestSuite", init_suite1, clean_suite1);
|
||||
if (NULL == pSuite) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
/* add the tests to the suite */
|
||||
if(!CU_add_test(pSuite, "wslay_frame_context_init",
|
||||
/* add the tests to the suite */
|
||||
if (!CU_add_test(pSuite, "wslay_frame_context_init",
|
||||
test_wslay_frame_context_init) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_recv", test_wslay_frame_recv) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_recv_1byte",
|
||||
@ -90,8 +82,23 @@ int main(void)
|
||||
test_wslay_frame_send_too_large_payload) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_send_ctrl_frame_too_large_payload",
|
||||
test_wslay_frame_send_ctrl_frame_too_large_payload) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write", test_wslay_frame_write) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_fragmented",
|
||||
test_wslay_frame_write_fragmented) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_interleaved_ctrl_frame",
|
||||
test_wslay_frame_write_interleaved_ctrl_frame) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_1byte_masked",
|
||||
test_wslay_frame_write_1byte_masked) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_zero_payloadlen",
|
||||
test_wslay_frame_write_zero_payloadlen) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_too_large_payload",
|
||||
test_wslay_frame_write_too_large_payload) ||
|
||||
!CU_add_test(pSuite, "wslay_frame_write_ctrl_frame_too_large_payload",
|
||||
test_wslay_frame_write_ctrl_frame_too_large_payload) ||
|
||||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg",
|
||||
test_wslay_event_send_fragmented_msg) ||
|
||||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_empty_data",
|
||||
test_wslay_event_send_fragmented_msg_empty_data) ||
|
||||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_with_ctrl",
|
||||
test_wslay_event_send_fragmented_msg_with_ctrl) ||
|
||||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_with_rsv1",
|
||||
@ -124,20 +131,32 @@ int main(void)
|
||||
test_wslay_event_message_too_big) ||
|
||||
!CU_add_test(pSuite, "wslay_event_config_set_allowed_rsv_bits",
|
||||
test_wslay_event_config_set_allowed_rsv_bits) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg",
|
||||
test_wslay_event_write_fragmented_msg) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_empty_data",
|
||||
test_wslay_event_write_fragmented_msg_empty_data) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_with_ctrl",
|
||||
test_wslay_event_write_fragmented_msg_with_ctrl) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_with_rsv1",
|
||||
test_wslay_event_write_fragmented_msg_with_rsv1) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_msg_with_rsv1",
|
||||
test_wslay_event_write_msg_with_rsv1) ||
|
||||
!CU_add_test(pSuite, "wslay_event_write_ctrl_msg_first",
|
||||
test_wslay_event_write_ctrl_msg_first) ||
|
||||
!CU_add_test(pSuite, "wslay_queue", test_wslay_queue)) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
/* Run all tests using the CUnit Basic interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_tests_failed = CU_get_number_of_tests_failed();
|
||||
CU_cleanup_registry();
|
||||
if (CU_get_error() == CUE_SUCCESS) {
|
||||
return (int)num_tests_failed;
|
||||
} else {
|
||||
printf("CUnit Error: %s\n", CU_get_error_msg());
|
||||
return CU_get_error();
|
||||
}
|
||||
/* Run all tests using the CUnit Basic interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_tests_failed = CU_get_number_of_tests_failed();
|
||||
CU_cleanup_registry();
|
||||
if (CU_get_error() == CUE_SUCCESS) {
|
||||
return (int)num_tests_failed;
|
||||
} else {
|
||||
printf("CUnit Error: %s\n", CU_get_error_msg());
|
||||
return CU_get_error();
|
||||
}
|
||||
}
|
||||
|
430
deps/wslay/tests/wslay_event_test.c
vendored
430
deps/wslay/tests/wslay_event_test.c
vendored
@ -32,8 +32,8 @@
|
||||
|
||||
struct scripted_data_feed {
|
||||
uint8_t data[8192];
|
||||
uint8_t* datamark;
|
||||
uint8_t* datalimit;
|
||||
uint8_t *datamark;
|
||||
uint8_t *datalimit;
|
||||
size_t feedseq[8192];
|
||||
size_t seqidx;
|
||||
};
|
||||
@ -49,44 +49,43 @@ struct my_user_data {
|
||||
};
|
||||
|
||||
static void scripted_data_feed_init(struct scripted_data_feed *df,
|
||||
const uint8_t *data, size_t data_length)
|
||||
{
|
||||
const uint8_t *data, size_t data_length) {
|
||||
memset(df, 0, sizeof(struct scripted_data_feed));
|
||||
memcpy(df->data, data, data_length);
|
||||
if (data_length) {
|
||||
memcpy(df->data, data, data_length);
|
||||
}
|
||||
df->datamark = df->data;
|
||||
df->datalimit = df->data+data_length;
|
||||
df->datalimit = df->data + data_length;
|
||||
df->feedseq[0] = data_length;
|
||||
}
|
||||
|
||||
static ssize_t scripted_read_callback
|
||||
(wslay_event_context_ptr ctx,
|
||||
uint8_t *data, size_t len, const union wslay_event_msg_source *source,
|
||||
int *eof, void *user_data)
|
||||
{
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed*)source->data;
|
||||
static ssize_t
|
||||
scripted_read_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
||||
const union wslay_event_msg_source *source, int *eof,
|
||||
void *user_data) {
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed *)source->data;
|
||||
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||
memcpy(data, df->datamark, wlen);
|
||||
df->datamark += wlen;
|
||||
if(wlen <= len) {
|
||||
if (wlen <= len) {
|
||||
++df->seqidx;
|
||||
} else {
|
||||
df->feedseq[df->seqidx] -= wlen;
|
||||
}
|
||||
if(df->datamark == df->datalimit) {
|
||||
if (df->datamark == df->datalimit) {
|
||||
*eof = 1;
|
||||
}
|
||||
return wlen;
|
||||
}
|
||||
|
||||
static ssize_t scripted_recv_callback(wslay_event_context_ptr ctx,
|
||||
uint8_t* data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
struct scripted_data_feed *df = ((struct my_user_data*)user_data)->df;
|
||||
uint8_t *data, size_t len, int flags,
|
||||
void *user_data) {
|
||||
struct scripted_data_feed *df = ((struct my_user_data *)user_data)->df;
|
||||
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||
memcpy(data, df->datamark, wlen);
|
||||
df->datamark += wlen;
|
||||
if(wlen <= len) {
|
||||
if (wlen <= len) {
|
||||
++df->seqidx;
|
||||
} else {
|
||||
df->feedseq[df->seqidx] -= wlen;
|
||||
@ -96,45 +95,38 @@ static ssize_t scripted_recv_callback(wslay_event_context_ptr ctx,
|
||||
|
||||
static ssize_t accumulator_send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
struct accumulator *acc = ((struct my_user_data*)user_data)->acc;
|
||||
assert(acc->length+len < sizeof(acc->buf));
|
||||
memcpy(acc->buf+acc->length, buf, len);
|
||||
int flags, void *user_data) {
|
||||
struct accumulator *acc = ((struct my_user_data *)user_data)->acc;
|
||||
assert(acc->length + len < sizeof(acc->buf));
|
||||
memcpy(acc->buf + acc->length, buf, len);
|
||||
acc->length += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t one_accumulator_send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
struct accumulator *acc = ((struct my_user_data*)user_data)->acc;
|
||||
int flags, void *user_data) {
|
||||
struct accumulator *acc = ((struct my_user_data *)user_data)->acc;
|
||||
assert(len > 0);
|
||||
memcpy(acc->buf+acc->length, buf, 1);
|
||||
memcpy(acc->buf + acc->length, buf, 1);
|
||||
acc->length += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t fail_recv_callback(wslay_event_context_ptr ctx,
|
||||
uint8_t* data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
static ssize_t fail_recv_callback(wslay_event_context_ptr ctx, uint8_t *data,
|
||||
size_t len, int flags, void *user_data) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t fail_send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *buf, size_t len, int flags,
|
||||
void* user_data)
|
||||
{
|
||||
void *user_data) {
|
||||
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void test_wslay_event_send_fragmented_msg(void)
|
||||
{
|
||||
void test_wslay_event_send_fragmented_msg(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
@ -142,11 +134,8 @@ void test_wslay_event_send_fragmented_msg(void)
|
||||
const char msg[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c,
|
||||
0x80, 0x02, 0x6c, 0x6f
|
||||
};
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
|
||||
const uint8_t ans[] = {0x01, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -166,8 +155,33 @@ void test_wslay_event_send_fragmented_msg(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_fragmented_msg_with_ctrl(void)
|
||||
{
|
||||
void test_wslay_event_send_fragmented_msg_empty_data(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {0x81, 0x00};
|
||||
scripted_data_feed_init(&df, NULL, 0);
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
memset(&acc, 0, sizeof(acc));
|
||||
ud.acc = &acc;
|
||||
wslay_event_context_server_init(&ctx, &callbacks, &ud);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.source.data = &df;
|
||||
arg.read_callback = scripted_read_callback;
|
||||
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
|
||||
CU_ASSERT(0 == wslay_event_send(ctx));
|
||||
CU_ASSERT_EQUAL(2, acc.length);
|
||||
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_fragmented_msg_with_ctrl(void) {
|
||||
int i;
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
@ -178,11 +192,11 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
struct wslay_event_msg ctrl_arg;
|
||||
const uint8_t ans[] = {
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x80, 0x02, 0x6c, 0x6f /* "lo" */
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x80, 0x02, 0x6c, 0x6f /* "lo" */
|
||||
};
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -205,7 +219,7 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
|
||||
ctrl_arg.msg_length = 0;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &ctrl_arg));
|
||||
CU_ASSERT(2 == wslay_event_get_queued_msg_count(ctx));
|
||||
for(i = 0; i < 10; ++i) {
|
||||
for (i = 0; i < 10; ++i) {
|
||||
CU_ASSERT(0 == wslay_event_send(ctx));
|
||||
}
|
||||
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
|
||||
@ -214,8 +228,7 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_fragmented_msg_with_rsv1(void)
|
||||
{
|
||||
void test_wslay_event_send_fragmented_msg_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
@ -223,11 +236,8 @@ void test_wslay_event_send_fragmented_msg_with_rsv1(void)
|
||||
const char msg[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0x41, 0x03, 0x48, 0x65, 0x6c,
|
||||
0x80, 0x02, 0x6c, 0x6f
|
||||
};
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
|
||||
const uint8_t ans[] = {0x41, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -249,8 +259,7 @@ void test_wslay_event_send_fragmented_msg_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_msg_with_rsv1(void)
|
||||
{
|
||||
void test_wslay_event_send_msg_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
@ -258,7 +267,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
|
||||
const char msg[] = "Hello";
|
||||
struct wslay_event_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -270,7 +279,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.msg = (const uint8_t*)msg;
|
||||
arg.msg = (const uint8_t *)msg;
|
||||
arg.msg_length = 5;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
|
||||
CU_ASSERT(0 == wslay_event_send(ctx));
|
||||
@ -279,8 +288,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_ctrl_msg_first(void)
|
||||
{
|
||||
void test_wslay_event_send_ctrl_msg_first(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
@ -288,8 +296,8 @@ void test_wslay_event_send_ctrl_msg_first(void)
|
||||
const char msg[] = "Hello";
|
||||
struct wslay_event_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
@ -302,7 +310,7 @@ void test_wslay_event_send_ctrl_msg_first(void)
|
||||
arg.msg_length = 0;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.msg = (const uint8_t*)msg;
|
||||
arg.msg = (const uint8_t *)msg;
|
||||
arg.msg_length = 5;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
|
||||
CU_ASSERT(0 == wslay_event_send(ctx));
|
||||
@ -311,8 +319,7 @@ void test_wslay_event_send_ctrl_msg_first(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_send_ctrl_msg_with_rsv1(void)
|
||||
{
|
||||
void test_wslay_event_send_ctrl_msg_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct wslay_event_msg arg;
|
||||
@ -331,15 +338,14 @@ void test_wslay_event_send_ctrl_msg_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_queue_close(void)
|
||||
{
|
||||
void test_wslay_event_queue_close(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
const char msg[] = "H";
|
||||
const uint8_t ans[] = {
|
||||
0x88, 0x03, 0x03, 0xf1, 0x48 /* "H" */
|
||||
0x88, 0x03, 0x03, 0xf1, 0x48 /* "H" */
|
||||
};
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
@ -347,7 +353,7 @@ void test_wslay_event_queue_close(void)
|
||||
ud.acc = &acc;
|
||||
wslay_event_context_server_init(&ctx, &callbacks, &ud);
|
||||
CU_ASSERT(0 == wslay_event_queue_close(ctx, WSLAY_CODE_MESSAGE_TOO_BIG,
|
||||
(const uint8_t*)msg, 1));
|
||||
(const uint8_t *)msg, 1));
|
||||
CU_ASSERT(0 == wslay_event_send(ctx));
|
||||
CU_ASSERT(5 == acc.length);
|
||||
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
|
||||
@ -355,14 +361,13 @@ void test_wslay_event_queue_close(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_queue_close_without_code(void)
|
||||
{
|
||||
void test_wslay_event_queue_close_without_code(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
const uint8_t ans[] = { 0x88, 0x00 };
|
||||
struct wslay_event_msg ping = { WSLAY_PING, NULL, 0 };
|
||||
const uint8_t ans[] = {0x88, 0x00};
|
||||
struct wslay_event_msg ping = {WSLAY_PING, NULL, 0};
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
memset(&acc, 0, sizeof(acc));
|
||||
@ -375,19 +380,17 @@ void test_wslay_event_queue_close_without_code(void)
|
||||
CU_ASSERT(2 == acc.length);
|
||||
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
|
||||
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
|
||||
CU_ASSERT(WSLAY_CODE_NO_STATUS_RCVD ==
|
||||
wslay_event_get_status_code_sent(ctx));
|
||||
CU_ASSERT(WSLAY_CODE_NO_STATUS_RCVD == wslay_event_get_status_code_sent(ctx));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_recv_close_without_code(void)
|
||||
{
|
||||
void test_wslay_event_recv_close_without_code(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
const uint8_t msg[] = { 0x88u, 0x00 };
|
||||
const uint8_t msg[] = {0x88u, 0x00};
|
||||
struct scripted_data_feed df;
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
ud.df = &df;
|
||||
@ -399,23 +402,22 @@ void test_wslay_event_recv_close_without_code(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_reply_close(void)
|
||||
{
|
||||
void test_wslay_event_reply_close(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
/* Masked close frame with code = 1009, reason = "Hello" */
|
||||
const uint8_t msg[] = { 0x88u, 0x87u, 0x00u, 0x00u, 0x00u, 0x00u,
|
||||
0x03, 0xf1, /* 1009 */
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
const uint8_t msg[] = {
|
||||
0x88u, 0x87u, 0x00u, 0x00u, 0x00u, 0x00u, 0x03, 0xf1, /* 1009 */
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
const uint8_t ans[] = { 0x88u, 0x07u,
|
||||
0x03, 0xf1, /* 1009 */
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
const uint8_t ans[] = {
|
||||
0x88u, 0x07u, 0x03, 0xf1, /* 1009 */
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -445,8 +447,7 @@ void test_wslay_event_reply_close(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_no_more_msg(void)
|
||||
{
|
||||
void test_wslay_event_no_more_msg(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -456,8 +457,7 @@ void test_wslay_event_no_more_msg(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_callback_failure(void)
|
||||
{
|
||||
void test_wslay_event_callback_failure(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
@ -472,9 +472,8 @@ void test_wslay_event_callback_failure(void)
|
||||
|
||||
static void no_buffering_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
if(arg->opcode == WSLAY_PING) {
|
||||
void *user_data) {
|
||||
if (arg->opcode == WSLAY_PING) {
|
||||
CU_ASSERT(3 == arg->msg_length);
|
||||
CU_ASSERT(0 == memcmp("Foo", arg->msg, arg->msg_length));
|
||||
} else {
|
||||
@ -483,18 +482,17 @@ static void no_buffering_callback(wslay_event_context_ptr ctx,
|
||||
}
|
||||
}
|
||||
|
||||
void test_wslay_event_no_buffering(void)
|
||||
{
|
||||
void test_wslay_event_no_buffering(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
const uint8_t msg[] = {
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x89, 0x03, 0x46, 0x6f, 0x6f, /* ping with "Foo" */
|
||||
0x80, 0x02, 0x6c, 0x6f, /* "lo" */
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x89, 0x03, 0x46, 0x6f, 0x6f, /* ping with "Foo" */
|
||||
0x80, 0x02, 0x6c, 0x6f, /* "lo" */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
ud.df = &df;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -510,35 +508,33 @@ void test_wslay_event_no_buffering(void)
|
||||
static void
|
||||
text_rsv1_on_msg_recv_callback(wslay_event_context_ptr ctx,
|
||||
const struct wslay_event_on_msg_recv_arg *arg,
|
||||
void *user_data)
|
||||
{
|
||||
void *user_data) {
|
||||
CU_ASSERT(WSLAY_TEXT_FRAME == arg->opcode);
|
||||
CU_ASSERT(WSLAY_RSV1_BIT == arg->rsv);
|
||||
}
|
||||
|
||||
void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
{
|
||||
void test_wslay_event_recv_text_frame_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
const uint8_t msg[] = {
|
||||
0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00 // "Hello" pm-deflate
|
||||
0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00 // "Hello" pm-deflate
|
||||
};
|
||||
const uint8_t fragmented[] = {
|
||||
0x41, 0x03, 0xf2, 0x48, 0xcd, // First fragment
|
||||
0x80, 0x04, 0xc9, 0xc9, 0x07, 0x00 // Second fragment, RSV1 bit off
|
||||
0x41, 0x03, 0xf2, 0x48, 0xcd, // First fragment
|
||||
0x80, 0x04, 0xc9, 0xc9, 0x07, 0x00 // Second fragment, RSV1 bit off
|
||||
};
|
||||
const uint8_t bad_fragment[] = {
|
||||
0x41, 0x03, 0xf2, 0x48, 0xcd,
|
||||
0xc0, 0x04, 0xc9, 0xc9, 0x07, 0x00 // RSV1 bit on
|
||||
0x41, 0x03, 0xf2, 0x48, 0xcd, 0xc0,
|
||||
0x04, 0xc9, 0xc9, 0x07, 0x00 // RSV1 bit on
|
||||
};
|
||||
const uint8_t pingmsg[] = {
|
||||
0xc9, 0x03, 0x46, 0x6f, 0x6f /* ping with "Foo" */
|
||||
0xc9, 0x03, 0x46, 0x6f, 0x6f /* ping with "Foo" */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
|
||||
/* Message marked with RSV1 should skip UTF-8 validation */
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
ud.df = &df;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -551,7 +547,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
|
||||
/* UTF-8 validation is skipped for continuation frames if the
|
||||
* initial frame was marked with RSV1 bit */
|
||||
scripted_data_feed_init(&df, (const uint8_t*)fragmented, sizeof(fragmented));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)fragmented, sizeof(fragmented));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
ud.df = &df;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -563,7 +559,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
|
||||
/* disallow RSV1 */
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
wslay_event_context_client_init(&ctx, &callbacks, &ud);
|
||||
CU_ASSERT(0 == wslay_event_recv(ctx));
|
||||
/* Close frame must be queued */
|
||||
@ -571,8 +567,8 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
|
||||
/* RSV1 is not allowed in continuation frame */
|
||||
scripted_data_feed_init(&df, (const uint8_t*)bad_fragment,
|
||||
sizeof(bad_fragment));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)bad_fragment,
|
||||
sizeof(bad_fragment));
|
||||
wslay_event_context_client_init(&ctx, &callbacks, &ud);
|
||||
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
|
||||
CU_ASSERT(0 == wslay_event_recv(ctx));
|
||||
@ -581,7 +577,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
|
||||
/* RSV1 is not allowed in ping frame */
|
||||
scripted_data_feed_init(&df, (const uint8_t*)pingmsg, sizeof(pingmsg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)pingmsg, sizeof(pingmsg));
|
||||
wslay_event_context_client_init(&ctx, &callbacks, &ud);
|
||||
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
|
||||
CU_ASSERT(0 == wslay_event_recv(ctx));
|
||||
@ -590,21 +586,21 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_frame_too_big(void)
|
||||
{
|
||||
void test_wslay_event_frame_too_big(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
/* Masked text frame */
|
||||
const uint8_t msg[] = { 0x81, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
const uint8_t msg[] = {
|
||||
0x81, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
const uint8_t ans[] = { 0x88, 0x02,
|
||||
0x03, 0xf1 /* 1009 */
|
||||
const uint8_t ans[] = {
|
||||
0x88, 0x02, 0x03, 0xf1 /* 1009 */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -623,23 +619,23 @@ void test_wslay_event_frame_too_big(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_message_too_big(void)
|
||||
{
|
||||
void test_wslay_event_message_too_big(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct my_user_data ud;
|
||||
struct accumulator acc;
|
||||
/* Masked text 2 frames */
|
||||
const uint8_t msg[] = { 0x01, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, /* "Hello" */
|
||||
0x80, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
const uint8_t msg[] = {
|
||||
0x01, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, /* "Hello" */
|
||||
0x80, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
const uint8_t ans[] = { 0x88, 0x02,
|
||||
0x03, 0xf1 /* 1009 */
|
||||
const uint8_t ans[] = {
|
||||
0x88, 0x02, 0x03, 0xf1 /* 1009 */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
@ -658,8 +654,7 @@ void test_wslay_event_message_too_big(void)
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_config_set_allowed_rsv_bits(void)
|
||||
{
|
||||
void test_wslay_event_config_set_allowed_rsv_bits(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
|
||||
@ -683,3 +678,164 @@ void test_wslay_event_config_set_allowed_rsv_bits(void)
|
||||
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_fragmented_msg(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
const char msg[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {0x01, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
|
||||
uint8_t buf[1024];
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.source.data = &df;
|
||||
arg.read_callback = scripted_read_callback;
|
||||
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
|
||||
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_fragmented_msg_empty_data(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {0x81, 0x00};
|
||||
uint8_t buf[1024];
|
||||
scripted_data_feed_init(&df, NULL, 0);
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.source.data = &df;
|
||||
arg.read_callback = scripted_read_callback;
|
||||
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
|
||||
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_fragmented_msg_with_ctrl(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
const char msg[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
struct wslay_event_msg ctrl_arg;
|
||||
const uint8_t ans[] = {
|
||||
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x80, 0x02, 0x6c, 0x6f /* "lo" */
|
||||
};
|
||||
uint8_t buf[1024];
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.source.data = &df;
|
||||
arg.read_callback = scripted_read_callback;
|
||||
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
|
||||
CU_ASSERT(1 == wslay_event_get_queued_msg_count(ctx));
|
||||
CU_ASSERT(0 == wslay_event_get_queued_msg_length(ctx));
|
||||
CU_ASSERT(4 == wslay_event_write(ctx, buf, 4));
|
||||
|
||||
memset(&ctrl_arg, 0, sizeof(ctrl_arg));
|
||||
ctrl_arg.opcode = WSLAY_PING;
|
||||
ctrl_arg.msg_length = 0;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &ctrl_arg));
|
||||
CU_ASSERT(2 == wslay_event_get_queued_msg_count(ctx));
|
||||
CU_ASSERT(7 == wslay_event_write(ctx, buf + 4, sizeof(buf) - 4));
|
||||
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_fragmented_msg_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
const char msg[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_event_fragmented_msg arg;
|
||||
const uint8_t ans[] = {0x41, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
|
||||
uint8_t buf[1024];
|
||||
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
|
||||
df.feedseq[0] = 3;
|
||||
df.feedseq[1] = 2;
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.send_callback = accumulator_send_callback;
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.source.data = &df;
|
||||
arg.read_callback = scripted_read_callback;
|
||||
CU_ASSERT(0 ==
|
||||
wslay_event_queue_fragmented_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
|
||||
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_msg_with_rsv1(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
const char msg[] = "Hello";
|
||||
struct wslay_event_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
uint8_t buf[1024];
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.msg = (const uint8_t *)msg;
|
||||
arg.msg_length = 5;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
|
||||
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_event_write_ctrl_msg_first(void) {
|
||||
wslay_event_context_ptr ctx;
|
||||
struct wslay_event_callbacks callbacks;
|
||||
const char msg[] = "Hello";
|
||||
struct wslay_event_msg arg;
|
||||
const uint8_t ans[] = {
|
||||
0x89, 0x00, /* unmasked ping */
|
||||
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
uint8_t buf[1024];
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
wslay_event_context_server_init(&ctx, &callbacks, NULL);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.opcode = WSLAY_PING;
|
||||
arg.msg_length = 0;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
|
||||
arg.opcode = WSLAY_TEXT_FRAME;
|
||||
arg.msg = (const uint8_t *)msg;
|
||||
arg.msg_length = 5;
|
||||
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
|
||||
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
|
||||
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
|
||||
wslay_event_context_free(ctx);
|
||||
}
|
||||
|
7
deps/wslay/tests/wslay_event_test.h
vendored
7
deps/wslay/tests/wslay_event_test.h
vendored
@ -26,6 +26,7 @@
|
||||
#define WSLAY_EVENT_TEST_H
|
||||
|
||||
void test_wslay_event_send_fragmented_msg(void);
|
||||
void test_wslay_event_send_fragmented_msg_empty_data(void);
|
||||
void test_wslay_event_send_fragmented_msg_with_ctrl(void);
|
||||
void test_wslay_event_send_fragmented_msg_with_rsv1(void);
|
||||
void test_wslay_event_send_msg_with_rsv1(void);
|
||||
@ -42,5 +43,11 @@ void test_wslay_event_recv_text_frame_with_rsv1(void);
|
||||
void test_wslay_event_frame_too_big(void);
|
||||
void test_wslay_event_message_too_big(void);
|
||||
void test_wslay_event_config_set_allowed_rsv_bits(void);
|
||||
void test_wslay_event_write_fragmented_msg(void);
|
||||
void test_wslay_event_write_fragmented_msg_empty_data(void);
|
||||
void test_wslay_event_write_fragmented_msg_with_ctrl(void);
|
||||
void test_wslay_event_write_fragmented_msg_with_rsv1(void);
|
||||
void test_wslay_event_write_msg_with_rsv1(void);
|
||||
void test_wslay_event_write_ctrl_msg_first(void);
|
||||
|
||||
#endif /* WSLAY_EVENT_TEST_H */
|
||||
|
449
deps/wslay/tests/wslay_frame_test.c
vendored
449
deps/wslay/tests/wslay_frame_test.c
vendored
@ -30,8 +30,7 @@
|
||||
|
||||
#include "wslay_frame.h"
|
||||
|
||||
void test_wslay_frame_context_init(void)
|
||||
{
|
||||
void test_wslay_frame_context_init(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks;
|
||||
int user_data;
|
||||
@ -42,30 +41,30 @@ void test_wslay_frame_context_init(void)
|
||||
|
||||
struct scripted_data_feed {
|
||||
uint8_t data[8192];
|
||||
uint8_t* datamark;
|
||||
uint8_t* datalimit;
|
||||
uint8_t *datamark;
|
||||
uint8_t *datalimit;
|
||||
size_t feedseq[8192];
|
||||
size_t seqidx;
|
||||
};
|
||||
|
||||
static void scripted_data_feed_init(struct scripted_data_feed *df,
|
||||
uint8_t *data, size_t data_length)
|
||||
{
|
||||
uint8_t *data, size_t data_length) {
|
||||
memset(df, 0, sizeof(struct scripted_data_feed));
|
||||
memcpy(df->data, data, data_length);
|
||||
if (data_length) {
|
||||
memcpy(df->data, data, data_length);
|
||||
}
|
||||
df->datamark = df->data;
|
||||
df->datalimit = df->data+data_length;
|
||||
df->datalimit = df->data + data_length;
|
||||
df->feedseq[0] = data_length;
|
||||
}
|
||||
|
||||
static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed*)user_data;
|
||||
static ssize_t scripted_recv_callback(uint8_t *data, size_t len, int flags,
|
||||
void *user_data) {
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed *)user_data;
|
||||
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||
memcpy(data, df->datamark, wlen);
|
||||
df->datamark += wlen;
|
||||
if(wlen <= len) {
|
||||
if (wlen <= len) {
|
||||
++df->seqidx;
|
||||
} else {
|
||||
df->feedseq[df->seqidx] -= wlen;
|
||||
@ -73,14 +72,13 @@ static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
|
||||
return wlen;
|
||||
}
|
||||
|
||||
static ssize_t scripted_send_callback(const uint8_t* data, size_t len,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed*)user_data;
|
||||
static ssize_t scripted_send_callback(const uint8_t *data, size_t len,
|
||||
int flags, void *user_data) {
|
||||
struct scripted_data_feed *df = (struct scripted_data_feed *)user_data;
|
||||
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||
memcpy(df->datamark, data, wlen);
|
||||
df->datamark += wlen;
|
||||
if(wlen <= len) {
|
||||
if (wlen <= len) {
|
||||
++df->seqidx;
|
||||
} else {
|
||||
df->feedseq[df->seqidx] -= wlen;
|
||||
@ -88,17 +86,14 @@ static ssize_t scripted_send_callback(const uint8_t* data, size_t len,
|
||||
return wlen;
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv(void)
|
||||
{
|
||||
void test_wslay_frame_recv(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
|
||||
0x4du, 0x51u, 0x58u };
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
|
||||
@ -114,28 +109,25 @@ void test_wslay_frame_recv(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_1byte(void)
|
||||
{
|
||||
void test_wslay_frame_recv_1byte(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
size_t i;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
|
||||
0x4du, 0x51u, 0x58u };
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
for(i = 0; i < sizeof(msg); ++i) {
|
||||
for (i = 0; i < sizeof(msg); ++i) {
|
||||
df.feedseq[i] = 1;
|
||||
}
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
|
||||
for(i = 0; i < 4; ++i) {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
CU_ASSERT(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
|
||||
}
|
||||
for(i = 0; i < 5; ++i) {
|
||||
for (i = 0; i < 5; ++i) {
|
||||
CU_ASSERT(1 == wslay_frame_recv(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(1, iocb.fin);
|
||||
CU_ASSERT_EQUAL(0, iocb.rsv);
|
||||
@ -143,24 +135,21 @@ void test_wslay_frame_recv_1byte(void)
|
||||
CU_ASSERT_EQUAL(5, iocb.payload_length);
|
||||
CU_ASSERT_EQUAL(1, iocb.mask);
|
||||
CU_ASSERT_EQUAL(1, iocb.data_length);
|
||||
CU_ASSERT_EQUAL(msg[6+i]^msg[2+i%4], iocb.data[0]);
|
||||
CU_ASSERT_EQUAL(msg[6 + i] ^ msg[2 + i % 4], iocb.data[0]);
|
||||
}
|
||||
CU_ASSERT(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_fragmented(void)
|
||||
{
|
||||
void test_wslay_frame_recv_fragmented(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg[] = { 0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
|
||||
uint8_t msg[] = {0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = 5;
|
||||
df.feedseq[1] = 4;
|
||||
@ -187,23 +176,19 @@ void test_wslay_frame_recv_fragmented(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_interleaved_ctrl_frame(void)
|
||||
{
|
||||
void test_wslay_frame_recv_interleaved_ctrl_frame(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg[] = { 0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
/* ping with "Hello" */
|
||||
0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
|
||||
0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
|
||||
uint8_t msg[] = {0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
|
||||
/* ping with "Hello" */
|
||||
0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x80, 0x02, 0x6c,
|
||||
0x6f}; /* "lo" */
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = 5;
|
||||
df.feedseq[1] = 7,
|
||||
df.feedseq[2] = 4;
|
||||
df.feedseq[1] = 7, df.feedseq[2] = 4;
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
|
||||
CU_ASSERT(3 == wslay_frame_recv(ctx, &iocb));
|
||||
@ -236,16 +221,13 @@ void test_wslay_frame_recv_interleaved_ctrl_frame(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_zero_payloadlen(void)
|
||||
{
|
||||
void test_wslay_frame_recv_zero_payloadlen(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg[] = { 0x81, 0x00 }; /* "" */
|
||||
uint8_t msg[] = {0x81, 0x00}; /* "" */
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = 2;
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -261,15 +243,12 @@ void test_wslay_frame_recv_zero_payloadlen(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_too_large_payload(void)
|
||||
{
|
||||
void test_wslay_frame_recv_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t msg[] = { 0x81, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
uint8_t msg[] = {0x81, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = sizeof(msg);
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -278,15 +257,12 @@ void test_wslay_frame_recv_too_large_payload(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_ctrl_frame_too_large_payload(void)
|
||||
{
|
||||
void test_wslay_frame_recv_ctrl_frame_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t msg[] = { 0x88, 0x7e };
|
||||
uint8_t msg[] = {0x88, 0x7e};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = sizeof(msg);
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -295,15 +271,12 @@ void test_wslay_frame_recv_ctrl_frame_too_large_payload(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_minimum_ext_payload16(void)
|
||||
{
|
||||
void test_wslay_frame_recv_minimum_ext_payload16(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t msg[] = { 0x81, 0x7e, 0x00, 0x7d };
|
||||
uint8_t msg[] = {0x81, 0x7e, 0x00, 0x7d};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = sizeof(msg);
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -312,15 +285,12 @@ void test_wslay_frame_recv_minimum_ext_payload16(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_recv_minimum_ext_payload64(void)
|
||||
{
|
||||
void test_wslay_frame_recv_minimum_ext_payload64(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { NULL,
|
||||
scripted_recv_callback,
|
||||
NULL };
|
||||
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
|
||||
struct scripted_data_feed df;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t msg[] = { 0x81, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
uint8_t msg[] = {0x81, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
scripted_data_feed_init(&df, msg, sizeof(msg));
|
||||
df.feedseq[0] = sizeof(msg);
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -335,34 +305,29 @@ struct accumulator {
|
||||
};
|
||||
|
||||
static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
struct accumulator *acc = (struct accumulator*)user_data;
|
||||
assert(acc->length+len < sizeof(acc->buf));
|
||||
memcpy(acc->buf+acc->length, buf, len);
|
||||
int flags, void *user_data) {
|
||||
struct accumulator *acc = (struct accumulator *)user_data;
|
||||
assert(acc->length + len < sizeof(acc->buf));
|
||||
memcpy(acc->buf + acc->length, buf, len);
|
||||
acc->length += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int static_genmask_callback(uint8_t *buf, size_t len,
|
||||
void* user_data)
|
||||
{
|
||||
static const uint8_t makskey[] = { 0x37u, 0xfau, 0x21u, 0x3du };
|
||||
static int static_genmask_callback(uint8_t *buf, size_t len, void *user_data) {
|
||||
static const uint8_t makskey[] = {0x37u, 0xfau, 0x21u, 0x3du};
|
||||
memcpy(buf, makskey, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_wslay_frame_send(void)
|
||||
{
|
||||
void test_wslay_frame_send(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
|
||||
NULL,
|
||||
static_genmask_callback };
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
|
||||
0x4du, 0x51u, 0x58u };
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
wslay_frame_context_init(&ctx, &callbacks, &acc);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
acc.length = 0;
|
||||
@ -370,7 +335,7 @@ void test_wslay_frame_send(void)
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 1;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = (const uint8_t*)"Hello";
|
||||
iocb.data = (const uint8_t *)"Hello";
|
||||
iocb.data_length = 5;
|
||||
CU_ASSERT(5 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg), acc.length);
|
||||
@ -379,17 +344,15 @@ void test_wslay_frame_send(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_fragmented(void)
|
||||
{
|
||||
void test_wslay_frame_send_fragmented(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
|
||||
NULL,
|
||||
static_genmask_callback };
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg1[] = { 0x01, 0x03, 0x48, 0x65, 0x6c }; /* "Hel" */
|
||||
uint8_t msg2[] = { 0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
|
||||
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c}; /* "Hel" */
|
||||
uint8_t msg2[] = {0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
|
||||
wslay_frame_context_init(&ctx, &callbacks, &acc);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
acc.length = 0;
|
||||
@ -397,7 +360,7 @@ void test_wslay_frame_send_fragmented(void)
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 3;
|
||||
iocb.data = (const uint8_t*)"Hel";
|
||||
iocb.data = (const uint8_t *)"Hel";
|
||||
iocb.data_length = 3;
|
||||
CU_ASSERT(3 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
|
||||
@ -407,7 +370,7 @@ void test_wslay_frame_send_fragmented(void)
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_CONTINUATION_FRAME;
|
||||
iocb.payload_length = 2;
|
||||
iocb.data = (const uint8_t*)"lo";
|
||||
iocb.data = (const uint8_t *)"lo";
|
||||
iocb.data_length = 2;
|
||||
CU_ASSERT(2 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg2), acc.length);
|
||||
@ -416,21 +379,19 @@ void test_wslay_frame_send_fragmented(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_interleaved_ctrl_frame(void)
|
||||
{
|
||||
void test_wslay_frame_send_interleaved_ctrl_frame(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
|
||||
NULL,
|
||||
static_genmask_callback };
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
/* text with "Hel", with fin = 0 */
|
||||
uint8_t msg1[] = { 0x01, 0x03, 0x48, 0x65, 0x6c };
|
||||
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c};
|
||||
/* ping with "Hello" */
|
||||
uint8_t msg2[] = { 0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f };
|
||||
uint8_t msg2[] = {0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f};
|
||||
/* text with "lo", continuation frame for msg1, with fin = 1 */
|
||||
uint8_t msg3[] = { 0x80, 0x02, 0x6c, 0x6f };
|
||||
uint8_t msg3[] = {0x80, 0x02, 0x6c, 0x6f};
|
||||
wslay_frame_context_init(&ctx, &callbacks, &acc);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
acc.length = 0;
|
||||
@ -438,7 +399,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 3;
|
||||
iocb.data = (const uint8_t*)"Hel";
|
||||
iocb.data = (const uint8_t *)"Hel";
|
||||
iocb.data_length = 3;
|
||||
CU_ASSERT(3 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
|
||||
@ -448,7 +409,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_PING;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = (const uint8_t*)"Hello";
|
||||
iocb.data = (const uint8_t *)"Hello";
|
||||
iocb.data_length = 5;
|
||||
CU_ASSERT(5 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg2), acc.length);
|
||||
@ -458,7 +419,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_CONTINUATION_FRAME;
|
||||
iocb.payload_length = 2;
|
||||
iocb.data = (const uint8_t*)"lo";
|
||||
iocb.data = (const uint8_t *)"lo";
|
||||
iocb.data_length = 2;
|
||||
CU_ASSERT(2 == wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(sizeof(msg3), acc.length);
|
||||
@ -467,21 +428,19 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_1byte_masked(void)
|
||||
{
|
||||
void test_wslay_frame_send_1byte_masked(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { scripted_send_callback,
|
||||
NULL,
|
||||
static_genmask_callback };
|
||||
struct wslay_frame_callbacks callbacks = {scripted_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
|
||||
0x4du, 0x51u, 0x58u };
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
uint8_t hello[] = "Hello";
|
||||
struct scripted_data_feed df;
|
||||
size_t i;
|
||||
scripted_data_feed_init(&df, NULL, 0);
|
||||
for(i = 0; i < sizeof(msg); ++i) {
|
||||
for (i = 0; i < sizeof(msg); ++i) {
|
||||
df.feedseq[i] = 1;
|
||||
}
|
||||
wslay_frame_context_init(&ctx, &callbacks, &df);
|
||||
@ -491,8 +450,8 @@ void test_wslay_frame_send_1byte_masked(void)
|
||||
iocb.mask = 1;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = hello;
|
||||
iocb.data_length = sizeof(hello)-1;
|
||||
for(i = 0; i < 5; ++i) {
|
||||
iocb.data_length = sizeof(hello) - 1;
|
||||
for (i = 0; i < 5; ++i) {
|
||||
CU_ASSERT_EQUAL(WSLAY_ERR_WANT_WRITE, wslay_frame_send(ctx, &iocb));
|
||||
}
|
||||
CU_ASSERT_EQUAL(5, wslay_frame_send(ctx, &iocb));
|
||||
@ -500,16 +459,14 @@ void test_wslay_frame_send_1byte_masked(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_zero_payloadlen(void)
|
||||
{
|
||||
void test_wslay_frame_send_zero_payloadlen(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
|
||||
NULL,
|
||||
static_genmask_callback };
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg[] = { 0x81, 0x00 }; /* "" */
|
||||
uint8_t msg[] = {0x81, 0x00}; /* "" */
|
||||
acc.length = 0;
|
||||
wslay_frame_context_init(&ctx, &callbacks, &acc);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
@ -525,8 +482,7 @@ void test_wslay_frame_send_zero_payloadlen(void)
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_too_large_payload(void)
|
||||
{
|
||||
void test_wslay_frame_send_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks;
|
||||
struct wslay_frame_iocb iocb;
|
||||
@ -536,14 +492,12 @@ void test_wslay_frame_send_too_large_payload(void)
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = UINT64_MAX;
|
||||
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT,
|
||||
wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT, wslay_frame_send(ctx, &iocb));
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_send_ctrl_frame_too_large_payload(void)
|
||||
{
|
||||
void test_wslay_frame_send_ctrl_frame_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks;
|
||||
struct wslay_frame_iocb iocb;
|
||||
@ -553,8 +507,213 @@ void test_wslay_frame_send_ctrl_frame_too_large_payload(void)
|
||||
iocb.opcode = WSLAY_PING;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 1024;
|
||||
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT,
|
||||
wslay_frame_send(ctx, &iocb));
|
||||
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT, wslay_frame_send(ctx, &iocb));
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = {NULL, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 1;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = (const uint8_t *)"Hello";
|
||||
iocb.data_length = 5;
|
||||
CU_ASSERT(11 ==
|
||||
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(iocb.data_length == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_fragmented(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = {NULL, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c}; /* "Hel" */
|
||||
uint8_t msg2[] = {0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 0;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 3;
|
||||
iocb.data = (const uint8_t *)"Hel";
|
||||
iocb.data_length = 3;
|
||||
CU_ASSERT(5 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(3 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg1, buf, sizeof(msg1)) == 0);
|
||||
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_CONTINUATION_FRAME;
|
||||
iocb.payload_length = 2;
|
||||
iocb.data = (const uint8_t *)"lo";
|
||||
iocb.data_length = 2;
|
||||
CU_ASSERT(4 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(2 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg2, buf, sizeof(msg2)) == 0);
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_interleaved_ctrl_frame(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = {NULL, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
/* text with "Hel", with fin = 0 */
|
||||
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c};
|
||||
/* ping with "Hello" */
|
||||
uint8_t msg2[] = {0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f};
|
||||
/* text with "lo", continuation frame for msg1, with fin = 1 */
|
||||
uint8_t msg3[] = {0x80, 0x02, 0x6c, 0x6f};
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 0;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 3;
|
||||
iocb.data = (const uint8_t *)"Hel";
|
||||
iocb.data_length = 3;
|
||||
CU_ASSERT(5 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(3 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg1, buf, sizeof(msg1)) == 0);
|
||||
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_PING;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = (const uint8_t *)"Hello";
|
||||
iocb.data_length = 5;
|
||||
CU_ASSERT(7 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(5 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg2, buf, sizeof(msg2)) == 0);
|
||||
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_CONTINUATION_FRAME;
|
||||
iocb.payload_length = 2;
|
||||
iocb.data = (const uint8_t *)"lo";
|
||||
iocb.data_length = 2;
|
||||
CU_ASSERT(4 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(2 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg3, buf, sizeof(msg3)) == 0);
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_1byte_masked(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = {NULL, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Masked text frame containing "Hello" */
|
||||
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
|
||||
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
|
||||
uint8_t hello[] = "Hello";
|
||||
size_t i;
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 1;
|
||||
iocb.payload_length = 5;
|
||||
iocb.data = hello;
|
||||
iocb.data_length = sizeof(hello) - 1;
|
||||
|
||||
CU_ASSERT_EQUAL(6, wslay_frame_write(ctx, &iocb, buf, 6, &wpayloadlen));
|
||||
CU_ASSERT(0 == wpayloadlen);
|
||||
|
||||
for (i = 0; i < 5; ++i) {
|
||||
CU_ASSERT_EQUAL(
|
||||
1, wslay_frame_write(ctx, &iocb, buf + 6 + i, 1, &wpayloadlen));
|
||||
CU_ASSERT(1 == wpayloadlen);
|
||||
|
||||
++iocb.data;
|
||||
--iocb.data_length;
|
||||
}
|
||||
|
||||
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_zero_payloadlen(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks = {NULL, NULL,
|
||||
static_genmask_callback};
|
||||
struct wslay_frame_iocb iocb;
|
||||
/* Unmasked message */
|
||||
uint8_t msg[] = {0x81, 0x00}; /* "" */
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 0;
|
||||
iocb.data_length = 0;
|
||||
CU_ASSERT(2 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
CU_ASSERT(0 == wpayloadlen);
|
||||
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_TEXT_FRAME;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = UINT64_MAX;
|
||||
CU_ASSERT_EQUAL(
|
||||
WSLAY_ERR_INVALID_ARGUMENT,
|
||||
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_wslay_frame_write_ctrl_frame_too_large_payload(void) {
|
||||
wslay_frame_context_ptr ctx;
|
||||
struct wslay_frame_callbacks callbacks;
|
||||
struct wslay_frame_iocb iocb;
|
||||
uint8_t buf[1024];
|
||||
size_t wpayloadlen;
|
||||
wslay_frame_context_init(&ctx, &callbacks, NULL);
|
||||
memset(&iocb, 0, sizeof(iocb));
|
||||
iocb.fin = 1;
|
||||
iocb.opcode = WSLAY_PING;
|
||||
iocb.mask = 0;
|
||||
iocb.payload_length = 1024;
|
||||
CU_ASSERT_EQUAL(
|
||||
WSLAY_ERR_INVALID_ARGUMENT,
|
||||
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
|
||||
|
||||
wslay_frame_context_free(ctx);
|
||||
}
|
||||
|
7
deps/wslay/tests/wslay_frame_test.h
vendored
7
deps/wslay/tests/wslay_frame_test.h
vendored
@ -42,5 +42,12 @@ void test_wslay_frame_send_1byte_masked(void);
|
||||
void test_wslay_frame_send_zero_payloadlen(void);
|
||||
void test_wslay_frame_send_too_large_payload(void);
|
||||
void test_wslay_frame_send_ctrl_frame_too_large_payload(void);
|
||||
void test_wslay_frame_write(void);
|
||||
void test_wslay_frame_write_fragmented(void);
|
||||
void test_wslay_frame_write_interleaved_ctrl_frame(void);
|
||||
void test_wslay_frame_write_1byte_masked(void);
|
||||
void test_wslay_frame_write_zero_payloadlen(void);
|
||||
void test_wslay_frame_write_too_large_payload(void);
|
||||
void test_wslay_frame_write_ctrl_frame_too_large_payload(void);
|
||||
|
||||
#endif /* WSLAY_FRAME_TEST_H */
|
||||
|
60
deps/wslay/tests/wslay_queue_test.c
vendored
60
deps/wslay/tests/wslay_queue_test.c
vendored
@ -27,33 +27,49 @@
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include "wslay_queue.h"
|
||||
#include "wslay_macro.h"
|
||||
|
||||
void test_wslay_queue(void)
|
||||
{
|
||||
int ints[] = { 1, 2, 3, 4, 5 };
|
||||
struct queue_entry {
|
||||
struct wslay_queue_entry qe;
|
||||
int value;
|
||||
};
|
||||
|
||||
void test_wslay_queue(void) {
|
||||
struct queue_entry ents[] = {
|
||||
{{0}, 1}, {{0}, 2}, {{0}, 3}, {{0}, 4}, {{0}, 5},
|
||||
};
|
||||
int i;
|
||||
struct wslay_queue *queue = wslay_queue_new();
|
||||
CU_ASSERT(wslay_queue_empty(queue));
|
||||
for(i = 0; i < 5; ++i) {
|
||||
wslay_queue_push(queue, &ints[i]);
|
||||
CU_ASSERT_EQUAL(ints[0], *(int*)(wslay_queue_top(queue)));
|
||||
CU_ASSERT(!wslay_queue_empty(queue));
|
||||
struct wslay_queue queue;
|
||||
wslay_queue_init(&queue);
|
||||
CU_ASSERT(wslay_queue_empty(&queue));
|
||||
for (i = 0; i < 5; ++i) {
|
||||
wslay_queue_push(&queue, &ents[i].qe);
|
||||
CU_ASSERT_EQUAL(ents[0].value, wslay_struct_of(wslay_queue_top(&queue),
|
||||
struct queue_entry, qe)
|
||||
->value);
|
||||
CU_ASSERT(!wslay_queue_empty(&queue));
|
||||
}
|
||||
for(i = 0; i < 5; ++i) {
|
||||
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
|
||||
wslay_queue_pop(queue);
|
||||
for (i = 0; i < 5; ++i) {
|
||||
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
|
||||
struct queue_entry, qe)
|
||||
->value);
|
||||
wslay_queue_pop(&queue);
|
||||
}
|
||||
CU_ASSERT(wslay_queue_empty(queue));
|
||||
CU_ASSERT(wslay_queue_empty(&queue));
|
||||
|
||||
for(i = 0; i < 5; ++i) {
|
||||
wslay_queue_push_front(queue, &ints[i]);
|
||||
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
|
||||
CU_ASSERT(!wslay_queue_empty(queue));
|
||||
for (i = 0; i < 5; ++i) {
|
||||
wslay_queue_push_front(&queue, &ents[i].qe);
|
||||
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
|
||||
struct queue_entry, qe)
|
||||
->value);
|
||||
CU_ASSERT(!wslay_queue_empty(&queue));
|
||||
}
|
||||
for(i = 4; i >= 0; --i) {
|
||||
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
|
||||
wslay_queue_pop(queue);
|
||||
for (i = 4; i >= 0; --i) {
|
||||
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
|
||||
struct queue_entry, qe)
|
||||
->value);
|
||||
wslay_queue_pop(&queue);
|
||||
}
|
||||
CU_ASSERT(wslay_queue_empty(queue));
|
||||
wslay_queue_free(queue);
|
||||
CU_ASSERT(wslay_queue_empty(&queue));
|
||||
wslay_queue_deinit(&queue);
|
||||
}
|
||||
|
13
deps/wslay/tests/wslay_stack_test.c
vendored
13
deps/wslay/tests/wslay_stack_test.c
vendored
@ -28,19 +28,18 @@
|
||||
|
||||
#include "wslay_stack.h"
|
||||
|
||||
void test_wslay_stack()
|
||||
{
|
||||
int ints[] = { 1, 2, 3, 4, 5 };
|
||||
void test_wslay_stack() {
|
||||
int ints[] = {1, 2, 3, 4, 5};
|
||||
int i;
|
||||
struct wslay_stack *stack = wslay_stack_new();
|
||||
CU_ASSERT(wslay_stack_empty(stack));
|
||||
for(i = 0; i < 5; ++i) {
|
||||
for (i = 0; i < 5; ++i) {
|
||||
wslay_stack_push(stack, &ints[i]);
|
||||
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_stack_top(stack)));
|
||||
CU_ASSERT_EQUAL(ints[i], *(int *)(wslay_stack_top(stack)));
|
||||
CU_ASSERT(!wslay_stack_empty(stack));
|
||||
}
|
||||
for(i = 4; i >= 0; --i) {
|
||||
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_stack_top(stack)));
|
||||
for (i = 4; i >= 0; --i) {
|
||||
CU_ASSERT_EQUAL(ints[i], *(int *)(wslay_stack_top(stack)));
|
||||
wslay_stack_pop(stack);
|
||||
}
|
||||
CU_ASSERT(wslay_stack_empty(stack));
|
||||
|
Loading…
Reference in New Issue
Block a user