Added wslay WebSocket library.

I made following modifications to the original library: The doc
directory was removed. Made shared library disabled by
configure. Removed doc from SUBDIRS in Makefile.am.
pull/13/head
Tatsuhiro Tsujikawa 2012-03-21 00:46:16 +09:00
parent 41c77ab852
commit 86ecf36abb
41 changed files with 6186 additions and 0 deletions

29
deps/wslay/.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
*~
*.o
*.lo
*.la
depcomp
*.m4
Makefile
Makefile.in
libtool
missing
autom4te.cache/
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
install-sh
.deps/
.libs
lib/includes/wslay/wslayver.h
lib/libwslay.pc
ltmain.sh
stamp-h1
.deps/
INSTALL
.DS_STORE
tests/main

1
deps/wslay/AUTHORS vendored Normal file
View File

@ -0,0 +1 @@
Tatsuhiro Tsujikawa <t-tujikawa at users dot sourceforge dot net>

22
deps/wslay/COPYING vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0
deps/wslay/ChangeLog vendored Normal file
View File

30
deps/wslay/Makefile.am vendored Normal file
View File

@ -0,0 +1,30 @@
# Wslay - The WebSocket Library
# Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib tests
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = examples/Makefile \
examples/fork-echoserv.c \
examples/echoserv.cc \
examples/testclient.cc

41
deps/wslay/NEWS vendored Normal file
View File

@ -0,0 +1,41 @@
wslay 0.1.1
===========
Release Note
------------
This release fixes the example programs and tutorial. It does not
change library code at all, so the library version has not been
changed.
Changes
-------
* Fixed example source code and tutorial.
wslay 0.1.0
===========
Release Note
------------
This is the initial release of wslay WebSocket C library.
Wslay is a WebSocket library written in C. It implements the protocol
version 13 described in RFC 6455. This library offers 2 levels of API:
event-based API and frame-based low-level API. For event-based API, it
is suitable for non-blocking reactor pattern style. You can set
callbacks in various events. For frame-based API, you can send
WebSocket frame directly. Wslay only supports data transfer part of
WebSocket protocol and does not perform opening handshake in HTTP.
Wslay does not perform any I/O operations for its own. Instead, it
offers callbacks for them. This makes Wslay independent on any I/O
frameworks, SSL, sockets, etc. This makes Wslay protable across
various platforms and the application authors can choose freely IO
frameworks.
Visit http://wslay.sourceforge.net/ for the API reference and
tutorial.

1
deps/wslay/README vendored Normal file
View File

@ -0,0 +1 @@
See README.rst

32
deps/wslay/README.rst vendored Normal file
View File

@ -0,0 +1,32 @@
Wslay - The WebSocket library
=============================
Project Web: http://wslay.sourceforge.net/
Wslay is a WebSocket library written in C.
It implements the protocol version 13 described in
`RFC 6455 <http://tools.ietf.org/html/rfc6455>`_.
This library offers 2 levels of API:
event-based API and frame-based low-level API. For event-based API, it
is suitable for non-blocking reactor pattern style. You can set
callbacks in various events. For frame-based API, you can send
WebSocket frame directly. Wslay only supports data transfer part of
WebSocket protocol and does not perform opening handshake in HTTP.
Wslay supports:
* Text/Binary messages.
* Automatic ping reply.
* Callback interface.
* External event loop.
Wslay does not perform any I/O operations for its own. Instead, it
offers callbacks for them. This makes Wslay independent on any I/O
frameworks, SSL, sockets, etc. This makes Wslay protable across
various platforms and the application authors can choose freely I/O
frameworks.
See Autobahn test reports:
`server <http://wslay.sourceforge.net/autobahn/reports/servers/index.html>`_
and
`client <http://wslay.sourceforge.net/autobahn/reports/clients/index.html>`_.

104
deps/wslay/configure.ac vendored Normal file
View File

@ -0,0 +1,104 @@
dnl Wslay - The WebSocket Library
dnl Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
dnl Permission is hereby granted, free of charge, to any person obtaining
dnl a copy of this software and associated documentation files (the
dnl "Software"), to deal in the Software without restriction, including
dnl without limitation the rights to use, copy, modify, merge, publish,
dnl distribute, sublicense, and/or sell copies of the Software, and to
dnl permit persons to whom the Software is furnished to do so, subject to
dnl the following conditions:
dnl The above copyright notice and this permission notice shall be
dnl included in all copies or substantial portions of the Software.
dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
dnl EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
dnl MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
dnl NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
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)
LT_PREREQ([2.2.6])
AC_INIT([wslay], [0.1.1], [t-tujikawa@users.sourceforge.net])
LT_INIT([disable-shared])
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_REVISION, 0)
AC_SUBST(LT_AGE, 0)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE()
AC_CONFIG_HEADERS([config.h])
dnl Checks for programs
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PATH_PROG([SPHINX_BUILD], [sphinx-build])
AC_SUBST([SPHINX_BUILD])
AM_CONDITIONAL([HAVE_SPHINX_BUILD], [ test "x$SPHINX_BUILD" != "x" ])
# Checks for libraries.
AC_CHECK_LIB([cunit], [CU_initialize_registry],
[have_cunit=yes], [have_cunit=no])
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
# Checks for header files.
AC_CHECK_HEADERS([ \
arpa/inet.h \
netinet/in.h \
stddef.h \
stdint.h \
stdlib.h \
string.h \
unistd.h \
])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_CHECK_TYPES([ptrdiff_t])
AC_C_BIGENDIAN
# Checks for library functions.
AC_FUNC_MALLOC
AC_CHECK_FUNCS([ \
memmove \
memset \
ntohl \
ntohs \
htons
])
AC_CONFIG_FILES([
Makefile
lib/Makefile
lib/libwslay.pc
lib/includes/Makefile
lib/includes/wslay/wslayver.h
tests/Makefile
])
AC_OUTPUT
AC_MSG_NOTICE([summary of build options:
version: ${VERSION} shared $LT_CURRENT:$LT_REVISION:$LT_AGE
Host type: ${host}
Install prefix: ${prefix}
C compiler: ${CC}
CFlags: ${CFLAGS}
Library types: Shared=${enable_shared}, Static=${enable_static}
CUnit: ${have_cunit}
])

3
deps/wslay/examples/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
fork-echoserv
echoserv
testclient

606
deps/wslay/examples/echoserv.cc vendored Normal file
View File

@ -0,0 +1,606 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// WebSocket Echo Server
// This is suitable for Autobahn server test.
// g++ -Wall -O2 -g -o echoserv echoserv.cc -L../lib/.libs -I../lib/includes -lwslay -lnettle
// $ export LD_LIBRARY_PATH=../lib/.libs
// $ ./a.out 9000
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <cassert>
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <string>
#include <set>
#include <iomanip>
#include <fstream>
#include <nettle/base64.h>
#include <nettle/sha.h>
#include <wslay/wslay.h>
int create_listen_socket(const char *service)
{
struct addrinfo hints;
int sfd = -1;
int r;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
struct addrinfo *res;
r = getaddrinfo(0, service, &hints, &res);
if(r != 0) {
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
return -1;
}
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sfd == -1) {
continue;
}
int 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) {
break;
}
close(sfd);
}
freeaddrinfo(res);
if(listen(sfd, 16) == -1) {
perror("listen");
close(sfd);
return -1;
}
return sfd;
}
int make_non_block(int fd)
{
int flags, r;
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) {
return -1;
}
return 0;
}
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()));
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)
{
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()));
std::string res(&dst[0], &dst[dstlen]);
delete [] dst;
return res;
}
std::string create_acceptkey(const std::string& clientkey)
{
std::string s = clientkey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
return base64(sha1(s));
}
class EventHandler {
public:
virtual ~EventHandler() {}
virtual int on_read_event() = 0;
virtual int on_write_event() = 0;
virtual bool want_read() = 0;
virtual bool want_write() = 0;
virtual int fd() const = 0;
virtual bool finish() = 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 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,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data);
class EchoWebSocketHandler : public EventHandler {
public:
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
};
wslay_event_context_server_init(&ctx_, &callbacks, this);
}
virtual ~EchoWebSocketHandler()
{
wslay_event_context_free(ctx_);
shutdown(fd_, SHUT_WR);
close(fd_);
}
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) {
return 0;
} else {
return -1;
}
}
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) {
sflags |= MSG_MORE;
}
#endif // MSG_MORE
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 r;
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;
}
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 r = sv->send_data(data, len, flags);
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);
}
}
return r;
}
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;
ssize_t r = sv->recv_data(data, len, flags);
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) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
r = -1;
}
return r;
}
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
};
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) {
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) {
break;
}
ssize_t r;
while((r = write(fd_, resheaders_.c_str()+off_, len)) == -1 &&
errno == EINTR);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else {
perror("write");
return -1;
}
} else {
off_ += r;
}
}
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()) {
int fd = fd_;
fd_ = -1;
return new EchoWebSocketHandler(fd);
} else {
return 0;
}
}
private:
int fd_;
std::string headers_;
std::string resheaders_;
size_t off_;
};
class HttpHandshakeRecvHandler : public EventHandler {
public:
HttpHandshakeRecvHandler(int fd)
: fd_(fd)
{}
virtual ~HttpHandshakeRecvHandler()
{
if(fd_ != -1) {
close(fd_);
}
}
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) {
break;
} else {
perror("read");
return -1;
}
} else if(r == 0) {
std::cerr << "http_upgrade: Got EOF" << std::endl;
return -1;
} else {
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) {
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) {
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);
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()) {
int fd = fd_;
fd_ = -1;
return new HttpHandshakeSendHandler(fd, accept_key_);
} else {
return 0;
}
}
private:
int fd_;
std::string headers_;
std::string accept_key_;
};
class ListenEventHandler : public EventHandler {
public:
ListenEventHandler(int fd)
: fd_(fd), cfd_(-1)
{}
virtual ~ListenEventHandler()
{
close(fd_);
close(cfd_);
}
virtual int on_read_event()
{
if(cfd_ != -1) {
close(cfd_);
}
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) {
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) {
close(fd);
return 0;
}
return new HttpHandshakeRecvHandler(fd);
} else {
return 0;
}
}
private:
int fd_;
int cfd_;
};
int ctl_epollev(int epollfd, int op, EventHandler *handler)
{
epoll_event ev;
memset(&ev, 0, sizeof(ev));
int events = 0;
if(handler->want_read()) {
events |= EPOLLIN;
}
if(handler->want_write()) {
events |= EPOLLOUT;
}
ev.events = events;
ev.data.ptr = handler;
return epoll_ctl(epollfd, op, handler->fd(), &ev);
}
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) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
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) {
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -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))) {
handlers.erase(eh);
delete eh;
} else {
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) {
perror("epoll_ctl");
delete next;
}
} else {
perror("epoll_ctl");
delete next;
}
}
}
if(eh->finish()) {
handlers.erase(eh);
delete eh;
} else {
if(ctl_epollev(epollfd, EPOLL_CTL_MOD, eh) == -1) {
perror("epoll_ctl");
}
}
}
}
}
}
int main(int argc, char **argv)
{
if(argc < 2) {
std::cerr << "Usage: " << argv[0] << " PORT" << std::endl;
exit(EXIT_FAILURE);
}
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
int sfd = create_listen_socket(argv[1]);
if(sfd == -1) {
std::cerr << "Failed to create server socket" << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "WebSocket echo server, listening on " << argv[1] << std::endl;
reactor(sfd);
}

426
deps/wslay/examples/fork-echoserv.c vendored Normal file
View File

@ -0,0 +1,426 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* WebSocket Echo Server
* This is suitable for Autobahn server test.
*
* Dependency: nettle-dev
*
* To compile:
* $ gcc -Wall -O2 -g -o fork-echoserv fork-echoserv.c -L../lib/.libs -I../lib/includes -lwslay -lnettle
*
* To run:
* $ export LD_LIBRARY_PATH=../lib/.libs
* $ ./a.out 9000
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <nettle/base64.h>
#include <nettle/sha.h>
#include <wslay/wslay.h>
/*
* 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)
{
struct addrinfo hints, *res, *rp;
int sfd = -1;
int r;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
r = getaddrinfo(0, service, &hints, &res);
if(r != 0) {
fprintf(stderr, "getaddrinfo: %s", gai_strerror(r));
return -1;
}
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) {
continue;
}
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
(socklen_t)sizeof(val)) == -1) {
continue;
}
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
break;
}
close(sfd);
}
freeaddrinfo(res);
if(listen(sfd, 16) == -1) {
perror("listen");
close(sfd);
return -1;
}
return sfd;
}
/*
* Makes file descriptor *fd* non-blocking mode.
* This function returns 0, or returns -1.
*/
int make_non_block(int fd)
{
int flags, r;
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) {
perror("fcntl");
return -1;
}
return 0;
}
/*
* 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)
{
struct sha1_ctx ctx;
sha1_init(&ctx);
sha1_update(&ctx, src_length, src);
sha1_digest(&ctx, SHA1_DIGEST_SIZE, dst);
}
/*
* Base64-encode *src* and stores it in *dst*.
* 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)
{
struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
base64_encode_raw(dst, src_length, src);
}
#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
/*
* Create Server's accept key in *dst*.
* *client_key* is the value of |Sec-WebSocket-Key| header field in
* 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)
{
uint8_t sha1buf[20], key_src[60];
memcpy(key_src, client_key, 24);
memcpy(key_src+24, WS_GUID, 36);
sha1(sha1buf, key_src, sizeof(key_src));
base64((uint8_t*)dst, sha1buf, 20);
dst[BASE64_ENCODE_RAW_LENGTH(20)] = '\0';
}
/*
* Performs HTTP handshake. *fd* is the file descriptor of the
* connection to the client. This function returns 0 if it succeeds,
* or returns -1.
*/
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];
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) {
perror("read");
return -1;
} 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) {
break;
} else if(header_length == sizeof(header)) {
fprintf(stderr, "HTTP Handshake: Too large HTTP headers");
return -1;
}
}
}
if(strstr(header, "\r\nUpgrade: websocket\r\n") == NULL ||
strstr(header, "\r\nConnection: Upgrade\r\n") == NULL ||
(keyhdstart = strstr(header, "\r\nSec-WebSocket-Key:")) == NULL) {
fprintf(stderr, "HTTP Handshake: Missing required header fields");
return -1;
}
keyhdstart += 20;
for(; *keyhdstart == ' '; ++keyhdstart);
keyhdend = keyhdstart;
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;
}
create_accept_key(accept_key, keyhdstart);
snprintf(res_header, sizeof(res_header),
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"\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) {
perror("write");
return -1;
} else {
res_header_sent += r;
}
}
return 0;
}
/*
* This struct is passed as *user_data* in callback function. The
* *fd* member is the file descriptor of the connection to the client.
*/
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;
ssize_t r;
int sflags = 0;
#ifdef 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) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
}
}
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;
ssize_t r;
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) {
/* Unexpected EOF is also treated as an error */
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
r = -1;
}
return r;
}
void on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
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
};
wslay_event_queue_msg(ctx, &msgarg);
}
}
/*
* Communicate with the client. This function performs HTTP handshake
* and WebSocket data transfer until close handshake is done or an
* 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)
{
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 };
int val = 1;
struct pollfd event;
int res = 0;
if(http_handshake(fd) == -1) {
return -1;
}
if(make_non_block(fd) == -1) {
return -1;
}
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
== -1) {
perror("setsockopt: TCP_NODELAY");
return -1;
}
memset(&event, 0, sizeof(struct pollfd));
event.fd = fd;
event.events = POLLIN;
wslay_event_context_server_init(&ctx, &callbacks, &session);
/*
* 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)) {
int r;
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 either wslay_event_recv() or wslay_event_send() return
* non-zero value, it means serious error which prevents wslay
* library from processing further data, so WebSocket connection
* must be closed.
*/
res = -1;
break;
}
event.events = 0;
if(wslay_event_want_read(ctx)) {
event.events |= POLLIN;
}
if(wslay_event_want_write(ctx)) {
event.events |= POLLOUT;
}
}
return res;
}
/*
* Serves echo back service forever. *sfd* is the file descriptor of
* the server socket. when the incoming connection from the client is
* accepted, this function forks another process and the forked
* process communicates with client. The parent process goes back to
* the loop and can accept another client.
*/
void serve(int sfd)
{
while(1) {
int fd;
while((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR);
if(fd == -1) {
perror("accept");
} else {
int r = fork();
if(r == -1) {
perror("fork");
close(fd);
} else if(r == 0) {
int r = communicate(fd);
shutdown(fd, SHUT_WR);
close(fd);
if(r == 0) {
exit(EXIT_SUCCESS);
} else {
exit(EXIT_FAILURE);
}
}
}
}
}
int main(int argc, char **argv)
{
struct sigaction act;
int sfd;
if(argc < 2) {
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
sfd = create_listen_socket(argv[1]);
if(sfd == -1) {
fprintf(stderr, "Failed to create server socket\n");
exit(EXIT_FAILURE);
}
printf("WebSocket echo server, listening on %s\n", argv[1]);
serve(sfd);
return EXIT_SUCCESS;
}

524
deps/wslay/examples/testclient.cc vendored Normal file
View File

@ -0,0 +1,524 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// WebSocket Test Client for Autobahn client test
// $ g++ -Wall -O2 -g -o testclient testclient.cc -L../lib/.libs -I../lib/includes -lwslay -lnettle
// $ export LD_LIBRARY_PATH=../lib/.libs
// $ ./a.out localhost 9001
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <cassert>
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <string>
#include <set>
#include <iomanip>
#include <fstream>
#include <nettle/base64.h>
#include <nettle/sha.h>
#include <wslay/wslay.h>
int connect_to(const char *host, const char *service)
{
struct addrinfo hints;
int fd = -1;
int r;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *res;
r = getaddrinfo(host, service, &hints, &res);
if(r != 0) {
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
return -1;
}
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(fd == -1) {
continue;
}
while((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR);
if(r == 0) {
break;
}
close(fd);
fd = -1;
}
freeaddrinfo(res);
return fd;
}
int make_non_block(int fd)
{
int flags, r;
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) {
return -1;
}
return 0;
}
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()));
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)
{
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()));
std::string res(&dst[0], &dst[dstlen]);
delete [] dst;
return res;
}
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")
{
wslay_event_context_client_init(&ctx_, callbacks, this);
}
~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)
{
ssize_t r;
int sflags = 0;
#ifdef MSG_MORE
if(flags & WSLAY_MSG_MORE) {
sflags |= MSG_MORE;
}
#endif // MSG_MORE
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_);
memcpy(data, body_.c_str(), wlen);
body_off_ += wlen;
return wlen;
} else {
return 0;
}
}
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);
return r;
}
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);
}
void set_callbacks(const struct wslay_event_callbacks *callbacks)
{
wslay_event_config_set_callbacks(ctx_, callbacks);
}
private:
int fd_;
wslay_event_context_ptr ctx_;
std::string body_;
size_t body_off_;
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 r = ws->send_data(data, len, flags);
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);
}
}
return r;
}
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;
ssize_t r = ws->recv_data(data, len, flags);
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) {
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;
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;
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
};
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);
}
}
int send_http_handshake(int fd, const std::string& reqheader)
{
size_t off = 0;
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) {
perror("write");
return -1;
}
off += r;
}
return 0;
}
int recv_http_handshake(int fd, std::string& resheader)
{
char buf[4096];
while(1) {
ssize_t r;
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) {
break;
}
if(resheader.size() > 8192) {
std::cerr << "Too big response header" << std::endl;
return -1;
}
}
return 0;
}
std::string get_random16()
{
char buf[16];
std::fstream f("/dev/urandom");
f.read(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)
{
char buf[4096];
std::string client_key = base64(get_random16());
snprintf(buf, sizeof(buf),
"GET %s HTTP/1.1\r\n"
"Host: %s:%s\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: %s\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n",
path, host, service, client_key.c_str());
std::string reqheader = buf;
if(send_http_handshake(fd, reqheader) == -1) {
return -1;
}
std::string resheader;
if(recv_http_handshake(fd, resheader) == -1) {
return -1;
}
std::string::size_type keyhdstart;
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);
return 0;
} else {
return -1;
}
}
void ctl_epollev(int epollfd, int op, WebSocketClient& ws)
{
epoll_event ev;
memset(&ev, 0, sizeof(ev));
if(ws.want_read()) {
ev.events |= EPOLLIN;
}
if(ws.want_write()) {
ev.events |= EPOLLOUT;
}
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)
{
struct wslay_event_callbacks cb = *callbacks;
cb.recv_callback = feed_body_callback;
int fd = connect_to(host, service);
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) {
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) {
perror("setsockopt: TCP_NODELAY");
return -1;
}
WebSocketClient ws(fd, &cb, body);
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) {
perror("epoll_create");
return -1;
}
ctl_epollev(epollfd, EPOLL_CTL_ADD, ws);
static const size_t MAX_EVENTS = 1;
epoll_event events[MAX_EVENTS];
bool ok = true;
while(ws.want_read() || ws.want_write()) {
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -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)) {
ok = false;
break;
}
}
if(!ok) {
break;
}
ctl_epollev(epollfd, EPOLL_CTL_MOD, ws);
}
return ok ? 0 : -1;
}
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) {
return -1;
}
errno = 0;
int casecnt = strtol(casecntjson.c_str(), 0, 10);
if(errno == ERANGE) {
return -1;
} else {
return casecnt;
}
}
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
};
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)
{
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 */
};
return communicate(host, service, "/updateReports?&agent=wslay", &callbacks);
}
int main(int argc, char **argv)
{
if(argc < 2) {
std::cerr << "Usage: " << argv[0] << " HOST SERV" << std::endl;
exit(EXIT_FAILURE);
}
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
const char *host = argv[1];
const char *service = argv[2];
int casecnt = get_casecnt(host, service);
if(casecnt == -1) {
std::cerr << "Failed to get case count." << std::endl;
exit(EXIT_FAILURE);
}
for(int i = 1; i <= casecnt; ++i) {
std::cout << "Running test case " << i << std::endl;
if(run_testcase(host, service, i) == -1) {
std::cout << "Detected error during test" << std::endl;
}
}
if(update_reports(host, service) == -1) {
std::cerr << "Failed to update reports." << std::endl;
exit(EXIT_FAILURE);
}
}

42
deps/wslay/lib/Makefile.am vendored Normal file
View File

@ -0,0 +1,42 @@
# Wslay - The WebSocket Library
# Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = includes
AM_CFLAGS = -Wall
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libwslay.pc
DISTCLEANFILES = $(pkgconfig_DATA)
lib_LTLIBRARIES = libwslay.la
OBJECTS = wslay_frame.c wslay_event.c\
wslay_queue.c wslay_net.c
HFILES = wslay_frame.h wslay_event.h\
wslay_queue.h wlsay_net.h
libwslay_la_SOURCES = $(HFILES) $(OBJECTS)
libwslay_la_LDFLAGS = -no-undefined \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)

23
deps/wslay/lib/includes/Makefile.am vendored Normal file
View File

@ -0,0 +1,23 @@
# Wslay - The WebSocket Library
# Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
nobase_include_HEADERS = wslay/wslay.h wslay/wslayver.h

736
deps/wslay/lib/includes/wslay/wslay.h vendored Normal file
View File

@ -0,0 +1,736 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_H
#define WSLAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <wslay/wslayver.h>
enum wslay_error {
WSLAY_ERR_WANT_READ = -100,
WSLAY_ERR_WANT_WRITE = -101,
WSLAY_ERR_PROTO = -200,
WSLAY_ERR_INVALID_ARGUMENT = -300,
WSLAY_ERR_INVALID_CALLBACK = -301,
WSLAY_ERR_NO_MORE_MSG = -302,
WSLAY_ERR_CALLBACK_FAILURE = -400,
WSLAY_ERR_WOULDBLOCK = -401,
WSLAY_ERR_NOMEM = -500
};
/*
* Status codes defined in RFC6455
*/
enum wslay_status_code {
WSLAY_CODE_NORMAL_CLOSURE = 1000,
WSLAY_CODE_GOING_AWAY = 1001,
WSLAY_CODE_PROTOCOL_ERROR = 1002,
WSLAY_CODE_UNSUPPORTED_DATA = 1003,
WSLAY_CODE_NO_STATUS_RCVD = 1005,
WSLAY_CODE_ABNORMAL_CLOSURE = 1006,
WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA = 1007,
WSLAY_CODE_POLICY_VIOLATION = 1008,
WSLAY_CODE_MESSAGE_TOO_BIG = 1009,
WSLAY_CODE_MANDATORY_EXT = 1010,
WSLAY_CODE_INTERNAL_SERVER_ERROR = 1011,
WSLAY_CODE_TLS_HANDSHAKE = 1015
};
enum wslay_io_flags {
/*
* There is more data to send.
*/
WSLAY_MSG_MORE = 1
};
/*
* Callback function used by wslay_frame_send() function when it needs
* to send data. The implementation of this function must send at most
* len bytes of data in data. flags is the bitwise OR of zero or more
* of the following flag:
*
* WSLAY_MSG_MORE
* There is more data to send
*
* It provides some hints to tune performance and behaviour. user_data
* is one given in wslay_frame_context_init() function. The
* implementation of this function must return the number of bytes
* sent. If there is an error, return -1. The return value 0 is also
* treated an error by the library.
*/
typedef ssize_t (*wslay_frame_send_callback)(const uint8_t *data, size_t len,
int flags, void *user_data);
/*
* Callback function used by wslay_frame_recv() function when it needs
* more data. The implementation of this function must fill at most
* len bytes of data into buf. The memory area of buf is allocated by
* library and not be freed by the application code. flags is always 0
* in this version. user_data is one given in
* wslay_frame_context_init() function. The implementation of this
* function must return the number of bytes filled. If there is an
* error, return -1. The return value 0 is also treated an error by
* the library.
*/
typedef ssize_t (*wslay_frame_recv_callback)(uint8_t *buf, size_t len,
int flags, void *user_data);
/*
* Callback function used by wslay_frame_send() function when it needs
* new mask key. The implementation of this function must write
* exactly len bytes of mask key to buf. user_data is one given in
* wslay_frame_context_init() function. The implementation of this
* function return 0 on success. If there is an error, return -1.
*/
typedef int (*wslay_frame_genmask_callback)(uint8_t *buf, size_t len,
void *user_data);
struct wslay_frame_callbacks {
wslay_frame_send_callback send_callback;
wslay_frame_recv_callback recv_callback;
wslay_frame_genmask_callback genmask_callback;
};
/*
* The opcode defined in RFC6455.
*/
enum wslay_opcode {
WSLAY_CONTINUATION_FRAME = 0x0u,
WSLAY_TEXT_FRAME = 0x1u,
WSLAY_BINARY_FRAME = 0x2u,
WSLAY_CONNECTION_CLOSE = 0x8u,
WSLAY_PING = 0x9u,
WSLAY_PONG = 0xau
};
/*
* Macro that returns 1 if opcode is control frame opcode, otherwise
* returns 0.
*/
#define wslay_is_ctrl_frame(opcode) ((opcode >> 3) & 1)
/*
* Macros that returns reserved bits: RSV1, RSV2, RSV3. These macros
* assumes that rsv is constructed by ((RSV1 << 2) | (RSV2 << 1) |
* RSV3)
*/
#define wslay_get_rsv1(rsv) ((rsv >> 2) & 1)
#define wslay_get_rsv2(rsv) ((rsv >> 1) & 1)
#define wslay_get_rsv3(rsv) (rsv & 1)
struct wslay_frame_iocb {
/* 1 for fragmented final frame, 0 for otherwise */
uint8_t fin;
/*
* reserved 3 bits. rsv = ((RSV1 << 2) | (RSV << 1) | RSV3).
* RFC6455 requires 0 unless extensions are negotiated.
*/
uint8_t rsv;
/* 4 bit opcode */
uint8_t opcode;
/* payload length [0, 2**63-1] */
uint64_t payload_length;
/* 1 for masked frame, 0 for unmasked */
uint8_t mask;
/* part of payload data */
const uint8_t *data;
/* bytes of data defined above */
size_t data_length;
};
struct wslay_frame_context;
typedef struct wslay_frame_context *wslay_frame_context_ptr;
/*
* Initializes ctx using given callbacks and user_data. This function
* allocates memory for struct wslay_frame_context and stores the
* result to *ctx. The callback functions specified in callbacks are
* copied to ctx. user_data is stored in ctx and it will be passed to
* callback functions. When the user code finished using ctx, it must
* call wslay_frame_context_free to deallocate memory.
*/
int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
const struct wslay_frame_callbacks *callbacks,
void *user_data);
/*
* Deallocates memory pointed by ctx.
*/
void wslay_frame_context_free(wslay_frame_context_ptr ctx);
/*
* Send WebSocket frame specified in iocb. ctx must be initialized
* using wslay_frame_context_init() function. iocb->fin must be 1 if
* this is a fin frame, otherwise 0. iocb->rsv is reserved bits.
* iocb->opcode must be the opcode of this frame. iocb->mask must be
* 1 if this is masked frame, otherwise 0. iocb->payload_length is
* the payload_length of this frame. iocb->data must point to the
* payload data to be sent. iocb->data_length must be the length of
* the data. This function calls recv_callback function if it needs
* to send bytes. This function calls gen_mask_callback function if
* it needs new mask key. This function returns the number of payload
* bytes sent. Please note that it does not include any number of
* header bytes. If it cannot send any single bytes of payload, it
* returns WSLAY_ERR_WANT_WRITE. If the library detects error in iocb,
* this function returns WSLAY_ERR_INVALID_ARGUMENT. If callback
* functions report a failure, this function returns
* WSLAY_ERR_INVALID_CALLBACK. This function does not always send all
* given data in iocb. If there are remaining data to be sent, adjust
* data and data_length in iocb accordingly and call this function
* again.
*/
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb);
/*
* Receives WebSocket frame and stores it in iocb. This function
* returns the number of payload bytes received. This does not
* include header bytes. In this case, iocb will be populated as
* follows: iocb->fin is 1 if received frame is fin frame, otherwise
* 0. iocb->rsv is reserved bits of received frame. iocb->opcode is
* opcode of received frame. iocb->mask is 1 if received frame is
* masked, otherwise 0. iocb->payload_length is the payload length of
* received frame. iocb->data is pointed to the buffer containing
* received payload data. This buffer is allocated by the library and
* must be read-only. iocb->data_length is the number of payload
* bytes recieved. This function calls recv_callback if it needs to
* receive additional bytes. If it cannot receive any single bytes of
* payload, it returns WSLAY_ERR_WANT_READ. If the library detects
* protocol violation in a received frame, this function returns
* WSLAY_ERR_PROTO. If callback functions report a failure, this
* function returns WSLAY_ERR_INVALID_CALLBACK. This function does
* not always receive whole frame in a single call. If there are
* remaining data to be received, call this function again. This
* function ensures frame alignment.
*/
ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb);
struct wslay_event_context;
/* Pointer to the event-based API context */
typedef struct wslay_event_context *wslay_event_context_ptr;
struct wslay_event_on_msg_recv_arg {
/* reserved bits: rsv = (RSV1 << 2) | (RSV2 << 1) | RSV3 */
uint8_t rsv;
/* opcode */
uint8_t opcode;
/* received message */
const uint8_t *msg;
/* message length */
size_t msg_length;
/*
* Status code iff opcode == WSLAY_CONNECTION_CLOSE. If no status
* code is included in the close control frame, it is set to 0.
*/
uint16_t status_code;
};
/*
* Callback function invoked by wslay_event_recv() when a message is
* completely received.
*/
typedef void (*wslay_event_on_msg_recv_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
struct wslay_event_on_frame_recv_start_arg {
/* fin bit; 1 for final frame, or 0. */
uint8_t fin;
/* reserved bits: rsv = (RSV1 << 2) | (RSV2 << 1) | RSV3 */
uint8_t rsv;
/* opcode of the frame */
uint8_t opcode;
/* payload length of ths frame */
uint64_t payload_length;
};
/*
* Callback function invoked by wslay_event_recv() when a new frame
* starts to be received. This callback function is only invoked once
* for each frame.
*/
typedef void (*wslay_event_on_frame_recv_start_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
struct wslay_event_on_frame_recv_chunk_arg {
/* chunk of payload data */
const uint8_t *data;
/* length of data */
size_t data_length;
};
/*
* Callback function invoked by wslay_event_recv() when a chunk of
* frame payload is received.
*/
typedef void (*wslay_event_on_frame_recv_chunk_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when a frame is
* completely received.
*/
typedef void (*wslay_event_on_frame_recv_end_callback)
(wslay_event_context_ptr ctx, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when it wants to
* receive more data from peer. The implementation of this callback
* function must read data at most len bytes from peer and store them
* in buf and return the number of bytes read. flags is always 0 in
* this version.
*
* If there is an error, return -1 and set error code
* WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error(). Wslay
* event-based API on the whole assumes non-blocking I/O. If the cause
* of error is EAGAIN or EWOULDBLOCK, set WSLAY_ERR_WOULDBLOCK
* instead. This is important because it tells wslay_event_recv() to
* stop receiving further data and return.
*/
typedef ssize_t (*wslay_event_recv_callback)(wslay_event_context_ptr ctx,
uint8_t *buf, size_t len,
int flags, void *user_data);
/*
* Callback function invoked by wslay_event_send() when it wants to
* send more data to peer. The implementation of this callback
* function must send data at most len bytes to peer and return the
* number of bytes sent. flags is the bitwise OR of zero or more of
* the following flag:
*
* WSLAY_MSG_MORE
* There is more data to send
*
* It provides some hints to tune performance and behaviour.
*
* If there is an error, return -1 and set error code
* WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error(). Wslay
* event-based API on the whole assumes non-blocking I/O. If the cause
* of error is EAGAIN or EWOULDBLOCK, set WSLAY_ERR_WOULDBLOCK
* instead. This is important because it tells wslay_event_send() to
* stop sending data and return.
*/
typedef ssize_t (*wslay_event_send_callback)(wslay_event_context_ptr ctx,
const uint8_t *data, size_t len,
int flags, void *user_data);
/*
* Callback function invoked by wslay_event_send() when it wants new
* mask key. As described in RFC6455, only the traffic from WebSocket
* client is masked, so this callback function is only needed if an
* event-based API is initialized for WebSocket client use.
*/
typedef int (*wslay_event_genmask_callback)(wslay_event_context_ptr ctx,
uint8_t *buf, size_t len,
void *user_data);
struct wslay_event_callbacks {
wslay_event_recv_callback recv_callback;
wslay_event_send_callback send_callback;
wslay_event_genmask_callback genmask_callback;
wslay_event_on_frame_recv_start_callback on_frame_recv_start_callback;
wslay_event_on_frame_recv_chunk_callback on_frame_recv_chunk_callback;
wslay_event_on_frame_recv_end_callback on_frame_recv_end_callback;
wslay_event_on_msg_recv_callback on_msg_recv_callback;
};
/*
* Initializes ctx as WebSocket Server. user_data is an arbitrary
* pointer, which is directly passed to each callback functions as
* user_data argument.
*
* On success, returns 0. On error, returns one of following negative
* values:
*
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_context_server_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks, void *user_data);
/*
* Initializes ctx as WebSocket client. user_data is an arbitrary
* pointer, which is directly passed to each callback functions as
* user_data argument.
*
* On success, returns 0. On error, returns one of following negative
* values:
*
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_context_client_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks, void *user_data);
/*
* Releases allocated resources for ctx.
*/
void wslay_event_context_free(wslay_event_context_ptr ctx);
/*
* Enables or disables buffering of an entire message for non-control
* frames. If val is 0, buffering is enabled. Otherwise, buffering is
* disabled. If wslay_event_on_msg_recv_callback is invoked when
* buffering is disabled, the msg_length member of struct
* wslay_event_on_msg_recv_arg is set to 0.
*
* The control frames are always buffered regardless of this function call.
*
* This function must not be used after the first invocation of
* wslay_event_recv() function.
*/
void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val);
/*
* Sets maximum length of a message that can be received. The length
* of message is checked by wslay_event_recv() function. If the length
* of a message is larger than this value, reading operation is
* disabled (same effect with wslay_event_shutdown_read() call) and
* close control frame with WSLAY_CODE_MESSAGE_TOO_BIG is queued. If
* buffering for non-control frames is disabled, the library checks
* each frame payload length and does not check length of entire
* message.
*
* The default value is (1u << 31)-1.
*/
void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
uint64_t val);
/*
* Sets callbacks to ctx. The callbacks previouly set by this function
* or wslay_event_context_server_init() or
* wslay_event_context_client_init() are replaced with callbacks.
*/
void wslay_event_config_set_callbacks
(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
/*
* Receives messages from peer. When receiving
* messages, it uses wslay_event_recv_callback function. Single call
* of this function receives multiple messages until
* wslay_event_recv_callback function sets error code
* WSLAY_ERR_WOULDBLOCK.
*
* When close control frame is received, this function automatically
* queues close control frame. Also this function calls
* wslay_event_set_read_enabled() with second argument 0 to disable
* further read from peer.
*
* When ping control frame is received, this function automatically
* queues pong control frame.
*
* In case of a fatal errror which leads to negative return code, this
* function calls wslay_event_set_read_enabled() with second argument
* 0 to disable further read from peer.
*
* wslay_event_recv() returns 0 if it succeeds, or one of the
* following negative error codes:
*
* WSLAY_ERR_CALLBACK_FAILURE
* User defined callback function is failed.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*
* When negative error code is returned, application must not make any
* further call of wslay_event_recv() and must close WebSocket
* connection.
*/
int wslay_event_recv(wslay_event_context_ptr ctx);
/*
* Sends queued messages to peer. When sending a
* message, it uses wslay_event_send_callback function. Single call of
* wslay_event_send() sends multiple messages until
* wslay_event_send_callback sets error code WSLAY_ERR_WOULDBLOCK.
*
* If ctx is initialized for WebSocket client use, wslay_event_send()
* uses wslay_event_genmask_callback to get new mask key.
*
* When a message queued using wslay_event_queue_fragmented_msg() is
* sent, wslay_event_send() invokes
* wslay_event_fragmented_msg_callback for that message.
*
* After close control frame is sent, this function calls
* wslay_event_set_write_enabled() with second argument 0 to disable
* further transmission to peer.
*
* If there are any pending messages, wslay_event_want_write() returns
* 1, otherwise returns 0.
*
* In case of a fatal errror which leads to negative return code, this
* function calls wslay_event_set_write_enabled() with second argument
* 0 to disable further transmission to peer.
*
* wslay_event_send() returns 0 if it succeeds, or one of the
* following negative error codes:
*
* WSLAY_ERR_CALLBACK_FAILURE
* User defined callback function is failed.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*
* When negative error code is returned, application must not make any
* further call of wslay_event_send() and must close WebSocket
* connection.
*/
int wslay_event_send(wslay_event_context_ptr ctx);
struct wslay_event_msg {
uint8_t opcode;
const uint8_t *msg;
size_t msg_length;
};
/*
* Queues message specified in arg.
*
* This function supports both control and non-control messages and
* the given message is sent without fragmentation. If fragmentation
* is needed, use wslay_event_queue_fragmented_msg() function instead.
*
* This function just queues a message and does not send
* it. wslay_event_send() function call sends these queued messages.
*
* wslay_event_queue_msg() returns 0 if it succeeds, or returns the
* following negative error codes:
*
* WSLAY_ERR_NO_MORE_MSG
* Could not queue given message. The one of possible reason is that
* close control frame has been queued/sent and no further queueing
* message is not allowed.
*
* WSLAY_ERR_INVALID_ARGUMENT
* The given message is invalid.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_queue_msg(wslay_event_context_ptr ctx,
const struct wslay_event_msg *arg);
/*
* Specify "source" to generate message.
*/
union wslay_event_msg_source {
int fd;
void *data;
};
/*
* Callback function called by wslay_event_send() to read message data
* from source. The implementation of
* wslay_event_fragmented_msg_callback must store at most len bytes of
* data to buf and return the number of stored bytes. If all data is
* read (i.e., EOF), set *eof to 1. If no data can be generated at the
* moment, return 0. If there is an error, return -1 and set error
* code WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error().
*/
typedef ssize_t (*wslay_event_fragmented_msg_callback)
(wslay_event_context_ptr ctx,
uint8_t *buf, size_t len, const union wslay_event_msg_source *source,
int *eof, void *user_data);
struct wslay_event_fragmented_msg {
/* opcode */
uint8_t opcode;
/* "source" to generate message data */
union wslay_event_msg_source source;
/* Callback function to read message data from source. */
wslay_event_fragmented_msg_callback read_callback;
};
/*
* Queues a fragmented message specified in arg.
*
* This function supports non-control messages only. For control frames,
* use wslay_event_queue_msg() or wslay_event_queue_close().
*
* This function just queues a message and does not send
* it. wslay_event_send() function call sends these queued messages.
*
* wslay_event_queue_fragmented_msg() returns 0 if it succeeds, or
* returns the following negative error codes:
*
* WSLAY_ERR_NO_MORE_MSG
* Could not queue given message. The one of possible reason is that
* close control frame has been queued/sent and no further queueing
* message is not allowed.
*
* WSLAY_ERR_INVALID_ARGUMENT
* The given message is invalid.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_queue_fragmented_msg
(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
/*
* Queues close control frame. This function is provided just for
* convenience. wslay_event_queue_msg() can queue a close control
* frame as well. status_code is the status code of close control
* frame. reason is the close reason encoded in UTF-8. reason_length
* is the length of reason in bytes. reason_length must be less than
* 123 bytes.
*
* If status_code is 0, reason and reason_length is not used and close
* control frame with zero-length payload will be queued.
*
* This function just queues a message and does not send
* it. wslay_event_send() function call sends these queued messages.
*
* wslay_event_queue_close() returns 0 if it succeeds, or returns the
* following negative error codes:
*
* WSLAY_ERR_NO_MORE_MSG
* Could not queue given message. The one of possible reason is that
* close control frame has been queued/sent and no further queueing
* message is not allowed.
*
* WSLAY_ERR_INVALID_ARGUMENT
* The given message is invalid.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_queue_close(wslay_event_context_ptr ctx,
uint16_t status_code,
const uint8_t *reason, size_t reason_length);
/*
* Sets error code to tell the library there is an error. This
* function is typically used in user defined callback functions. See
* the description of callback function to know which error code
* should be used.
*/
void wslay_event_set_error(wslay_event_context_ptr ctx, int val);
/*
* Query whehter the library want to read more data from peer.
*
* wslay_event_want_read() returns 1 if the library want to read more
* data from peer, or returns 0.
*/
int wslay_event_want_read(wslay_event_context_ptr ctx);
/*
* Query whehter the library want to send more data to peer.
*
* wslay_event_want_write() returns 1 if the library want to send more
* data to peer, or returns 0.
*/
int wslay_event_want_write(wslay_event_context_ptr ctx);
/*
* Prevents the event-based API context from reading any further data
* from peer.
*
* This function may be used with wslay_event_queue_close() if the
* application detects error in the data received and wants to fail
* WebSocket connection.
*/
void wslay_event_shutdown_read(wslay_event_context_ptr ctx);
/*
* Prevents the event-based API context from sending any further data
* to peer.
*/
void wslay_event_shutdown_write(wslay_event_context_ptr ctx);
/*
* Returns 1 if the event-based API context allows read operation, or
* return 0.
*
* After wslay_event_shutdown_read() is called,
* wslay_event_get_read_enabled() returns 0.
*/
int wslay_event_get_read_enabled(wslay_event_context_ptr ctx);
/*
* Returns 1 if the event-based API context allows write operation, or
* return 0.
*
* After wslay_event_shutdown_write() is called,
* wslay_event_get_write_enabled() returns 0.
*/
int wslay_event_get_write_enabled(wslay_event_context_ptr ctx);
/*
* Returns 1 if a close control frame has been received from peer, or
* returns 0.
*/
int wslay_event_get_close_received(wslay_event_context_ptr ctx);
/*
* Returns 1 if a close control frame has been sent to peer, or
* returns 0.
*/
int wslay_event_get_close_sent(wslay_event_context_ptr ctx);
/*
* Returns status code received in close control frame. If no close
* control frame has not been received, returns
* WSLAY_CODE_ABNORMAL_CLOSURE. If received close control frame has no
* status code, returns WSLAY_CODE_NO_STATUS_RCVD.
*/
uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx);
/*
* Returns status code sent in close control frame. If no close
* control frame has not been sent, returns
* WSLAY_CODE_ABNORMAL_CLOSURE. If sent close control frame has no
* status code, returns WSLAY_CODE_NO_STATUS_RCVD.
*/
uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx);
/*
* Returns the number of queued messages.
*/
size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx);
/*
* Returns the sum of queued message length. It only counts the
* message length queued using wslay_event_queue_msg() or
* wslay_event_queue_close().
*/
size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx);
#ifdef __cplusplus
}
#endif
#endif /* WSLAY_H */

View File

@ -0,0 +1,31 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAYVER_H
#define WSLAYVER_H
/* Version number of wslay release */
#define WSLAY_VERSION "@PACKAGE_VERSION@"
#endif /* WSLAYVER_H */

33
deps/wslay/lib/libwslay.pc.in vendored Normal file
View File

@ -0,0 +1,33 @@
# Wslay - The WebSocket Library
# Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Wslay
Description: Low-level WebSockets library
URL: http://wslay.sourceforge.net/
Version: @VERSION@
Libs: -L${libdir} -lwslay
Cflags: -I${includedir}

984
deps/wslay/lib/wslay_event.c vendored Normal file
View File

@ -0,0 +1,984 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_event.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "wslay_queue.h"
#include "wslay_frame.h"
#include "wslay_net.h"
/* Start of utf8 dfa */
/* Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
* See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
*
* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define UTF8_ACCEPT 0
#define UTF8_REJECT 12
static const uint8_t utf8d[] = {
/*
* The first part of the table maps bytes to character classes that
* to reduce the size of the transition table and create bitmasks.
*/
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
/*
* The second part is a transition table that maps a combination
* of a state of the automaton and a character class to a state.
*/
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12,
};
static uint32_t
decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
uint32_t type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state + type];
return *state;
}
/* End of utf8 dfa */
static ssize_t wslay_event_frame_recv_callback(uint8_t *buf, size_t len,
int flags, void *user_data)
{
struct wslay_event_frame_user_data *e =
(struct wslay_event_frame_user_data*)user_data;
return e->ctx->callbacks.recv_callback(e->ctx, buf, len, flags, e->user_data);
}
static ssize_t wslay_event_frame_send_callback(const uint8_t *data, size_t len,
int flags, void *user_data)
{
struct wslay_event_frame_user_data *e =
(struct wslay_event_frame_user_data*)user_data;
return e->ctx->callbacks.send_callback(e->ctx, data, len, flags,
e->user_data);
}
static int wslay_event_frame_genmask_callback(uint8_t *buf, size_t len,
void *user_data)
{
struct wslay_event_frame_user_data *e =
(struct wslay_event_frame_user_data*)user_data;
return e->ctx->callbacks.genmask_callback(e->ctx, buf, len, e->user_data);
}
static int wslay_event_byte_chunk_init
(struct wslay_event_byte_chunk **chunk, size_t len)
{
*chunk = (struct wslay_event_byte_chunk*)malloc
(sizeof(struct wslay_event_byte_chunk));
if(*chunk == NULL) {
return WSLAY_ERR_NOMEM;
}
memset(*chunk, 0, sizeof(struct wslay_event_byte_chunk));
if(len) {
(*chunk)->data = (uint8_t*)malloc(len);
(*chunk)->data_length = len;
}
return 0;
}
static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c)
{
if(!c) {
return;
}
free(c->data);
free(c);
}
static void wslay_event_byte_chunk_copy(struct wslay_event_byte_chunk *c,
size_t off,
const uint8_t *data, size_t data_length)
{
memcpy(c->data+off, data, data_length);
}
static void wslay_event_imsg_set(struct wslay_event_imsg *m,
uint8_t fin, uint8_t rsv, uint8_t opcode)
{
m->fin = fin;
m->rsv = rsv;
m->opcode = opcode;
m->msg_length = 0;
}
static void wslay_event_imsg_chunks_free(struct wslay_event_imsg *m)
{
if(!m->chunks) {
return;
}
while(!wslay_queue_empty(m->chunks)) {
wslay_event_byte_chunk_free(wslay_queue_top(m->chunks));
wslay_queue_pop(m->chunks);
}
}
static void wslay_event_imsg_reset(struct wslay_event_imsg *m)
{
m->opcode = 0xffu;
m->utf8state = UTF8_ACCEPT;
wslay_event_imsg_chunks_free(m);
}
static int wslay_event_imsg_append_chunk(struct wslay_event_imsg *m, size_t len)
{
if(len == 0) {
return 0;
} else {
int r;
struct wslay_event_byte_chunk *chunk;
if((r = wslay_event_byte_chunk_init(&chunk, len)) != 0) {
return r;
}
if((r = wslay_queue_push(m->chunks, chunk)) != 0) {
return r;
}
m->msg_length += len;
return 0;
}
}
static int wslay_event_omsg_non_fragmented_init
(struct wslay_event_omsg **m, uint8_t opcode,
const uint8_t *msg, size_t msg_length)
{
*m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
if(!*m) {
return WSLAY_ERR_NOMEM;
}
memset(*m, 0, sizeof(struct wslay_event_omsg));
(*m)->fin = 1;
(*m)->opcode = opcode;
(*m)->type = WSLAY_NON_FRAGMENTED;
if(msg_length) {
(*m)->data = (uint8_t*)malloc(msg_length);
if(!(*m)->data) {
free(*m);
return WSLAY_ERR_NOMEM;
}
memcpy((*m)->data, msg, msg_length);
(*m)->data_length = msg_length;
}
return 0;
}
static int wslay_event_omsg_fragmented_init
(struct wslay_event_omsg **m, uint8_t opcode,
const union wslay_event_msg_source source,
wslay_event_fragmented_msg_callback read_callback)
{
*m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
if(!*m) {
return WSLAY_ERR_NOMEM;
}
memset(*m, 0, sizeof(struct wslay_event_omsg));
(*m)->opcode = opcode;
(*m)->type = WSLAY_FRAGMENTED;
(*m)->source = source;
(*m)->read_callback = read_callback;
return 0;
}
static void wslay_event_omsg_free(struct wslay_event_omsg *m)
{
if(!m) {
return;
}
free(m->data);
free(m);
}
static uint8_t* wslay_event_flatten_queue(struct wslay_queue *queue, size_t len)
{
if(len == 0) {
return NULL;
} else {
size_t off = 0;
uint8_t *buf = (uint8_t*)malloc(len);
if(!buf) {
return NULL;
}
while(!wslay_queue_empty(queue)) {
struct wslay_event_byte_chunk *chunk = wslay_queue_top(queue);
memcpy(buf+off, chunk->data, chunk->data_length);
off += chunk->data_length;
wslay_event_byte_chunk_free(chunk);
wslay_queue_pop(queue);
assert(off <= len);
}
assert(len == off);
return buf;
}
}
static int wslay_event_is_msg_queueable(wslay_event_context_ptr ctx)
{
return ctx->write_enabled && (ctx->close_status & WSLAY_CLOSE_QUEUED) == 0;
}
int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
const uint8_t *reason, size_t reason_length)
{
if(!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
} else if(reason_length > 123) {
return WSLAY_ERR_INVALID_ARGUMENT;
} else {
uint8_t msg[128];
size_t msg_length;
struct wslay_event_msg arg;
uint16_t ncode;
int r;
if(status_code == 0) {
msg_length = 0;
} else {
ncode = htons(status_code);
memcpy(msg, &ncode, 2);
memcpy(msg+2, reason, reason_length);
msg_length = reason_length+2;
}
arg.opcode = WSLAY_CONNECTION_CLOSE;
arg.msg = msg;
arg.msg_length = msg_length;
r = wslay_event_queue_msg(ctx, &arg);
if(r == 0) {
ctx->close_status |= WSLAY_CLOSE_QUEUED;
}
return r;
}
}
static int wslay_event_queue_close_wrapper
(wslay_event_context_ptr ctx, uint16_t status_code,
const uint8_t *reason, size_t reason_length)
{
int r;
ctx->read_enabled = 0;
if((r = wslay_event_queue_close(ctx, status_code, reason, reason_length)) &&
r != WSLAY_ERR_NO_MORE_MSG) {
return r;
}
return 0;
}
int wslay_event_queue_msg(wslay_event_context_ptr ctx,
const struct wslay_event_msg *arg)
{
int r;
struct wslay_event_omsg *omsg;
if(!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
}
if(wslay_is_ctrl_frame(arg->opcode) && arg->msg_length > 125) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if((r = wslay_event_omsg_non_fragmented_init
(&omsg, arg->opcode, arg->msg, arg->msg_length)) != 0) {
return r;
}
if(wslay_is_ctrl_frame(arg->opcode)) {
if((r = wslay_queue_push(ctx->send_ctrl_queue, omsg)) != 0) {
return r;
}
} else {
if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
return r;
}
}
++ctx->queued_msg_count;
ctx->queued_msg_length += arg->msg_length;
return 0;
}
int wslay_event_queue_fragmented_msg
(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg)
{
int r;
struct wslay_event_omsg *omsg;
if(!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
}
if(wslay_is_ctrl_frame(arg->opcode)) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if((r = wslay_event_omsg_fragmented_init
(&omsg, arg->opcode, arg->source, arg->read_callback)) != 0) {
return r;
}
if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
return r;
}
++ctx->queued_msg_count;
return 0;
}
void wslay_event_config_set_callbacks
(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks)
{
ctx->callbacks = *callbacks;
}
static int wslay_event_context_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks,
void *user_data)
{
int i, r;
struct wslay_frame_callbacks frame_callbacks = {
wslay_event_frame_send_callback,
wslay_event_frame_recv_callback,
wslay_event_frame_genmask_callback
};
*ctx = (wslay_event_context_ptr)malloc(sizeof(struct wslay_event_context));
if(!*ctx) {
return WSLAY_ERR_NOMEM;
}
memset(*ctx, 0, sizeof(struct wslay_event_context));
wslay_event_config_set_callbacks(*ctx, callbacks);
(*ctx)->user_data = user_data;
(*ctx)->frame_user_data.ctx = *ctx;
(*ctx)->frame_user_data.user_data = user_data;
if((r = wslay_frame_context_init(&(*ctx)->frame_ctx, &frame_callbacks,
&(*ctx)->frame_user_data)) != 0) {
wslay_event_context_free(*ctx);
return r;
}
(*ctx)->read_enabled = (*ctx)->write_enabled = 1;
(*ctx)->send_queue = wslay_queue_new();
if(!(*ctx)->send_queue) {
wslay_event_context_free(*ctx);
return WSLAY_ERR_NOMEM;
}
(*ctx)->send_ctrl_queue = wslay_queue_new();
if(!(*ctx)->send_ctrl_queue) {
wslay_event_context_free(*ctx);
return WSLAY_ERR_NOMEM;
}
(*ctx)->queued_msg_count = 0;
(*ctx)->queued_msg_length = 0;
for(i = 0; i < 2; ++i) {
wslay_event_imsg_reset(&(*ctx)->imsgs[i]);
(*ctx)->imsgs[i].chunks = wslay_queue_new();
if(!(*ctx)->imsgs[i].chunks) {
wslay_event_context_free(*ctx);
return WSLAY_ERR_NOMEM;
}
}
(*ctx)->imsg = &(*ctx)->imsgs[0];
(*ctx)->obufmark = (*ctx)->obuflimit = (*ctx)->obuf;
(*ctx)->status_code_sent = WSLAY_CODE_ABNORMAL_CLOSURE;
(*ctx)->status_code_recv = WSLAY_CODE_ABNORMAL_CLOSURE;
(*ctx)->max_recv_msg_length = (1u << 31)-1;
return 0;
}
int wslay_event_context_server_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks,
void *user_data)
{
int r;
if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
return r;
}
(*ctx)->server = 1;
return 0;
}
int wslay_event_context_client_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks,
void *user_data)
{
int r;
if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
return r;
}
(*ctx)->server = 0;
return 0;
}
void wslay_event_context_free(wslay_event_context_ptr ctx)
{
int i;
if(!ctx) {
return;
}
for(i = 0; i < 2; ++i) {
wslay_event_imsg_chunks_free(&ctx->imsgs[i]);
wslay_queue_free(ctx->imsgs[i].chunks);
}
if(ctx->send_queue) {
while(!wslay_queue_empty(ctx->send_queue)) {
wslay_event_omsg_free(wslay_queue_top(ctx->send_queue));
wslay_queue_pop(ctx->send_queue);
}
wslay_queue_free(ctx->send_queue);
}
if(ctx->send_ctrl_queue) {
while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
wslay_event_omsg_free(wslay_queue_top(ctx->send_ctrl_queue));
wslay_queue_pop(ctx->send_ctrl_queue);
}
wslay_queue_free(ctx->send_ctrl_queue);
}
wslay_frame_context_free(ctx->frame_ctx);
wslay_event_omsg_free(ctx->omsg);
free(ctx);
}
static void wslay_event_call_on_frame_recv_start_callback
(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
{
if(ctx->callbacks.on_frame_recv_start_callback) {
struct wslay_event_on_frame_recv_start_arg arg;
arg.fin = iocb->fin;
arg.rsv = iocb->rsv;
arg.opcode = iocb->opcode;
arg.payload_length = iocb->payload_length;
ctx->callbacks.on_frame_recv_start_callback(ctx, &arg, ctx->user_data);
}
}
static void wslay_event_call_on_frame_recv_chunk_callback
(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
{
if(ctx->callbacks.on_frame_recv_chunk_callback) {
struct wslay_event_on_frame_recv_chunk_arg arg = {
iocb->data, iocb->data_length
};
ctx->callbacks.on_frame_recv_chunk_callback(ctx, &arg, ctx->user_data);
}
};
static void wslay_event_call_on_frame_recv_end_callback
(wslay_event_context_ptr ctx)
{
if(ctx->callbacks.on_frame_recv_end_callback) {
ctx->callbacks.on_frame_recv_end_callback(ctx, ctx->user_data);
}
}
static int wslay_event_is_valid_status_code(uint16_t status_code)
{
return (1000 <= status_code && status_code <= 1011 &&
status_code != 1004 && status_code != 1005 && status_code != 1006) ||
(3000 <= status_code && status_code <= 4999);
}
static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx)
{
return (ctx->config & WSLAY_CONFIG_NO_BUFFERING) > 0;
}
int wslay_event_recv(wslay_event_context_ptr ctx)
{
struct wslay_frame_iocb iocb;
ssize_t r;
while(ctx->read_enabled) {
memset(&iocb, 0, sizeof(iocb));
r = wslay_frame_recv(ctx->frame_ctx, &iocb);
if(r >= 0) {
int new_frame = 0;
/* We only allow rsv == 0 ATM. */
if(iocb.rsv != 0 ||
((ctx->server && !iocb.mask) || (!ctx->server && iocb.mask))) {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
return r;
}
break;
}
if(ctx->imsg->opcode == 0xffu) {
if(iocb.opcode == WSLAY_TEXT_FRAME ||
iocb.opcode == WSLAY_BINARY_FRAME ||
iocb.opcode == WSLAY_CONNECTION_CLOSE ||
iocb.opcode == WSLAY_PING ||
iocb.opcode == WSLAY_PONG) {
wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
new_frame = 1;
} else {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
return r;
}
break;
}
} else if(ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) {
if(iocb.opcode == WSLAY_CONTINUATION_FRAME) {
ctx->imsg->fin = iocb.fin;
} else if(iocb.opcode == WSLAY_CONNECTION_CLOSE ||
iocb.opcode == WSLAY_PING ||
iocb.opcode == WSLAY_PONG) {
ctx->imsg = &ctx->imsgs[1];
wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
} else {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
return r;
}
break;
}
new_frame = 1;
}
if(new_frame) {
if(ctx->imsg->msg_length+iocb.payload_length >
ctx->max_recv_msg_length) {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) {
return r;
}
break;
}
ctx->ipayloadlen = iocb.payload_length;
wslay_event_call_on_frame_recv_start_callback(ctx, &iocb);
if(!wslay_event_config_get_no_buffering(ctx) ||
wslay_is_ctrl_frame(iocb.opcode)) {
if((r = wslay_event_imsg_append_chunk(ctx->imsg,
iocb.payload_length)) != 0) {
ctx->read_enabled = 0;
return r;
}
}
}
if(ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
size_t i;
if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
i = 2;
} else {
i = 0;
}
for(; i < iocb.data_length; ++i) {
uint32_t codep;
if(decode(&ctx->imsg->utf8state, &codep,
iocb.data[i]) == UTF8_REJECT) {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
return r;
}
break;
}
}
}
if(ctx->imsg->utf8state == UTF8_REJECT) {
break;
}
wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb);
if(iocb.data_length > 0) {
if(!wslay_event_config_get_no_buffering(ctx) ||
wslay_is_ctrl_frame(iocb.opcode)) {
struct wslay_event_byte_chunk *chunk;
chunk = wslay_queue_tail(ctx->imsg->chunks);
wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff,
iocb.data, iocb.data_length);
}
ctx->ipayloadoff += iocb.data_length;
}
if(ctx->ipayloadoff == ctx->ipayloadlen) {
if(ctx->imsg->fin &&
(ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) &&
ctx->imsg->utf8state != UTF8_ACCEPT) {
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
return r;
}
break;
}
wslay_event_call_on_frame_recv_end_callback(ctx);
if(ctx->imsg->fin) {
if(ctx->callbacks.on_msg_recv_callback ||
ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE ||
ctx->imsg->opcode == WSLAY_PING) {
struct wslay_event_on_msg_recv_arg arg;
uint16_t status_code = 0;
uint8_t *msg = NULL;
size_t msg_length = 0;
if(!wslay_event_config_get_no_buffering(ctx) ||
wslay_is_ctrl_frame(iocb.opcode)) {
msg = wslay_event_flatten_queue(ctx->imsg->chunks,
ctx->imsg->msg_length);
if(ctx->imsg->msg_length && !msg) {
ctx->read_enabled = 0;
return WSLAY_ERR_NOMEM;
}
msg_length = ctx->imsg->msg_length;
}
if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
const uint8_t *reason;
size_t reason_length;
if(ctx->imsg->msg_length >= 2) {
memcpy(&status_code, msg, 2);
status_code = ntohs(status_code);
if(!wslay_event_is_valid_status_code(status_code)) {
free(msg);
if((r = wslay_event_queue_close_wrapper
(ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
return r;
}
break;
}
reason = msg+2;
reason_length = ctx->imsg->msg_length-2;
} else {
reason = NULL;
reason_length = 0;
}
ctx->close_status |= WSLAY_CLOSE_RECEIVED;
ctx->status_code_recv =
status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
if((r = wslay_event_queue_close_wrapper
(ctx, status_code, reason, reason_length)) != 0) {
free(msg);
return r;
}
} else if(ctx->imsg->opcode == WSLAY_PING) {
struct wslay_event_msg arg = {
WSLAY_PONG, msg, ctx->imsg->msg_length
};
if((r = wslay_event_queue_msg(ctx, &arg)) &&
r != WSLAY_ERR_NO_MORE_MSG) {
ctx->read_enabled = 0;
free(msg);
return r;
}
}
if(ctx->callbacks.on_msg_recv_callback) {
arg.rsv = ctx->imsg->rsv;
arg.opcode = ctx->imsg->opcode;
arg.msg = msg;
arg.msg_length = msg_length;
arg.status_code = status_code;
ctx->error = 0;
ctx->callbacks.on_msg_recv_callback(ctx, &arg, ctx->user_data);
}
free(msg);
}
wslay_event_imsg_reset(ctx->imsg);
if(ctx->imsg == &ctx->imsgs[1]) {
ctx->imsg = &ctx->imsgs[0];
}
}
ctx->ipayloadlen = ctx->ipayloadoff = 0;
}
} else {
if(r != WSLAY_ERR_WANT_READ ||
(ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
if((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) {
return r;
}
return WSLAY_ERR_CALLBACK_FAILURE;
}
break;
}
}
return 0;
}
static void wslay_event_on_non_fragmented_msg_popped
(wslay_event_context_ptr ctx)
{
ctx->omsg->fin = 1;
ctx->opayloadlen = ctx->omsg->data_length;
ctx->opayloadoff = 0;
}
static struct wslay_event_omsg* wslay_event_send_ctrl_queue_pop
(wslay_event_context_ptr ctx)
{
/*
* If Close control frame is queued, we don't send any control frame
* other than Close.
*/
if(ctx->close_status & WSLAY_CLOSE_QUEUED) {
while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
wslay_queue_pop(ctx->send_ctrl_queue);
if(msg->opcode == WSLAY_CONNECTION_CLOSE) {
return msg;
} else {
wslay_event_omsg_free(msg);
}
}
return NULL;
} else {
struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
wslay_queue_pop(ctx->send_ctrl_queue);
return msg;
}
}
int wslay_event_send(wslay_event_context_ptr ctx)
{
struct wslay_frame_iocb iocb;
ssize_t r;
while(ctx->write_enabled &&
(!wslay_queue_empty(ctx->send_queue) ||
!wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg)) {
if(!ctx->omsg) {
if(wslay_queue_empty(ctx->send_ctrl_queue)) {
ctx->omsg = wslay_queue_top(ctx->send_queue);
wslay_queue_pop(ctx->send_queue);
} else {
ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
if(ctx->omsg == NULL) {
break;
}
}
if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
wslay_event_on_non_fragmented_msg_popped(ctx);
}
} else if(!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
ctx->frame_ctx->ostate == PREP_HEADER &&
!wslay_queue_empty(ctx->send_ctrl_queue)) {
if((r = wslay_queue_push_front(ctx->send_queue, ctx->omsg)) != 0) {
ctx->write_enabled = 0;
return r;
}
ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
if(ctx->omsg == NULL) {
break;
}
/* ctrl message has WSLAY_NON_FRAGMENTED */
wslay_event_on_non_fragmented_msg_popped(ctx);
}
if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = ctx->omsg->opcode;
iocb.mask = ctx->server^1;
iocb.data = ctx->omsg->data+ctx->opayloadoff;
iocb.data_length = ctx->opayloadlen-ctx->opayloadoff;
iocb.payload_length = ctx->opayloadlen;
r = wslay_frame_send(ctx->frame_ctx, &iocb);
if(r >= 0) {
ctx->opayloadoff += r;
if(ctx->opayloadoff == ctx->opayloadlen) {
--ctx->queued_msg_count;
ctx->queued_msg_length -= ctx->omsg->data_length;
if(ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
uint16_t status_code = 0;
ctx->write_enabled = 0;
ctx->close_status |= WSLAY_CLOSE_SENT;
if(ctx->omsg->data_length >= 2) {
memcpy(&status_code, ctx->omsg->data, 2);
status_code = ntohs(status_code);
}
ctx->status_code_sent =
status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
}
wslay_event_omsg_free(ctx->omsg);
ctx->omsg = NULL;
} else {
break;
}
} else {
if(r != WSLAY_ERR_WANT_WRITE ||
(ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
break;
}
} else {
if(ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
int eof = 0;
r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
&ctx->omsg->source,
&eof, ctx->user_data);
if(r == 0) {
break;
} else if(r < 0) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
ctx->obuflimit = ctx->obuf+r;
if(eof) {
ctx->omsg->fin = 1;
} else if(r == 0) {
break;
}
ctx->opayloadlen = r;
ctx->opayloadoff = 0;
}
memset(&iocb, 0, sizeof(iocb));
iocb.fin = ctx->omsg->fin;
iocb.opcode = ctx->omsg->opcode;
iocb.mask = ctx->server ? 0 : 1;
iocb.data = ctx->obufmark;
iocb.data_length = ctx->obuflimit-ctx->obufmark;
iocb.payload_length = ctx->opayloadlen;
r = wslay_frame_send(ctx->frame_ctx, &iocb);
if(r >= 0) {
ctx->obufmark += r;
if(ctx->obufmark == ctx->obuflimit) {
ctx->obufmark = ctx->obuflimit = ctx->obuf;
if(ctx->omsg->fin) {
--ctx->queued_msg_count;
wslay_event_omsg_free(ctx->omsg);
ctx->omsg = NULL;
} else {
ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
}
} else {
break;
}
} else {
if(r != WSLAY_ERR_WANT_WRITE ||
(ctx->error != WSLAY_ERR_WOULDBLOCK &&
ctx->error != 0)) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
break;
}
}
}
return 0;
}
void wslay_event_set_error(wslay_event_context_ptr ctx, int val)
{
ctx->error = val;
}
int wslay_event_want_read(wslay_event_context_ptr ctx)
{
return ctx->read_enabled;
}
int wslay_event_want_write(wslay_event_context_ptr ctx)
{
return ctx->write_enabled &&
(!wslay_queue_empty(ctx->send_queue) ||
!wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg);
}
void wslay_event_shutdown_read(wslay_event_context_ptr ctx)
{
ctx->read_enabled = 0;
}
void wslay_event_shutdown_write(wslay_event_context_ptr ctx)
{
ctx->write_enabled = 0;
}
int wslay_event_get_read_enabled(wslay_event_context_ptr ctx)
{
return ctx->read_enabled;
}
int wslay_event_get_write_enabled(wslay_event_context_ptr ctx)
{
return ctx->write_enabled;
}
int wslay_event_get_close_received(wslay_event_context_ptr ctx)
{
return (ctx->close_status & WSLAY_CLOSE_RECEIVED) > 0;
}
int wslay_event_get_close_sent(wslay_event_context_ptr ctx)
{
return (ctx->close_status & WSLAY_CLOSE_SENT) > 0;
}
void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val)
{
if(val) {
ctx->config |= WSLAY_CONFIG_NO_BUFFERING;
} else {
ctx->config &= ~WSLAY_CONFIG_NO_BUFFERING;
}
}
void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
uint64_t val)
{
ctx->max_recv_msg_length = val;
}
uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx)
{
return ctx->status_code_recv;
}
uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx)
{
return ctx->status_code_sent;
}
size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx)
{
return ctx->queued_msg_count;
}
size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx)
{
return ctx->queued_msg_length;
}

140
deps/wslay/lib/wslay_event.h vendored Normal file
View File

@ -0,0 +1,140 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_EVENT_H
#define WSLAY_EVENT_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <wslay/wslay.h>
struct wslay_stack;
struct wslay_queue;
struct wslay_event_byte_chunk {
uint8_t *data;
size_t data_length;
};
struct wslay_event_imsg {
uint8_t fin;
uint8_t rsv;
uint8_t opcode;
uint32_t utf8state;
struct wslay_queue *chunks;
size_t msg_length;
};
enum wslay_event_msg_type {
WSLAY_NON_FRAGMENTED,
WSLAY_FRAGMENTED
};
struct wslay_event_omsg {
uint8_t fin;
uint8_t opcode;
enum wslay_event_msg_type type;
uint8_t *data;
size_t data_length;
union wslay_event_msg_source source;
wslay_event_fragmented_msg_callback read_callback;
};
struct wslay_event_frame_user_data {
wslay_event_context_ptr ctx;
void *user_data;
};
enum wslay_event_close_status {
WSLAY_CLOSE_RECEIVED = 1 << 0,
WSLAY_CLOSE_QUEUED = 1 << 1,
WSLAY_CLOSE_SENT = 1 << 2,
};
enum wslay_event_config {
WSLAY_CONFIG_NO_BUFFERING = 1 << 0
};
struct wslay_event_context {
/* config status, bitwise OR of enum wslay_event_config values*/
uint32_t config;
/* maximum message length that can be received */
uint64_t max_recv_msg_length;
/* 1 if initialized for server, otherwise 0 */
uint8_t server;
/* bitwise OR of enum wslay_event_close_status values */
uint8_t close_status;
/* status code in received close control frame */
uint16_t status_code_recv;
/* status code in sent close control frame */
uint16_t status_code_sent;
wslay_frame_context_ptr frame_ctx;
/* 1 if reading is enabled, otherwise 0. Upon receiving close
control frame this value set to 0. If any errors in read
operation will also set this value to 0. */
uint8_t read_enabled;
/* 1 if writing is enabled, otherwise 0 Upon completing sending
close control frame, this value set to 0. If any errors in write
opration will also set this value to 0. */
uint8_t write_enabled;
/* imsg buffer to allow interleaved control frame between
non-control frames. */
struct wslay_event_imsg imsgs[2];
/* Pointer to imsgs to indicate current used buffer. */
struct wslay_event_imsg *imsg;
/* payload length of frame currently being received. */
uint64_t ipayloadlen;
/* next byte offset of payload currently being received. */
uint64_t ipayloadoff;
/* error value set by user callback */
int error;
/* Pointer to the message currently being sent. NULL if no message
is currently sent. */
struct wslay_event_omsg *omsg;
/* Queue for non-control frames */
struct wslay_queue/*<wslay_omsg*>*/ *send_queue;
/* Queue for control frames */
struct wslay_queue/*<wslay_omsg*>*/ *send_ctrl_queue;
/* Size of send_queue + size of send_ctrl_queue */
size_t queued_msg_count;
/* The sum of message length in send_queue */
size_t queued_msg_length;
/* Buffer used for fragmented messages */
uint8_t obuf[4096];
uint8_t *obuflimit;
uint8_t *obufmark;
/* payload length of frame currently being sent. */
uint64_t opayloadlen;
/* next byte offset of payload currently being sent. */
uint64_t opayloadoff;
struct wslay_event_callbacks callbacks;
struct wslay_event_frame_user_data frame_user_data;
void *user_data;
};
#endif /* WSLAY_EVENT_H */

342
deps/wslay/lib/wslay_frame.c vendored Normal file
View File

@ -0,0 +1,342 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_frame.h"
#include <stddef.h>
#include <string.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H
#include <assert.h>
#include "wslay_net.h"
#define wslay_min(A, B) (((A) < (B)) ? (A) : (B))
int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
const struct wslay_frame_callbacks *callbacks,
void *user_data)
{
*ctx = (wslay_frame_context_ptr)malloc(sizeof(struct wslay_frame_context));
if(ctx == NULL) {
return -1;
}
memset(*ctx, 0, sizeof(struct wslay_frame_context));
(*ctx)->istate = RECV_HEADER1;
(*ctx)->ireqread = 2;
(*ctx)->ostate = PREP_HEADER;
(*ctx)->user_data = user_data;
(*ctx)->ibufmark = (*ctx)->ibuflimit = (*ctx)->ibuf;
(*ctx)->callbacks = *callbacks;
return 0;
}
void wslay_frame_context_free(wslay_frame_context_ptr ctx)
{
free(ctx);
}
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb)
{
if(iocb->data_length > iocb->payload_length) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(ctx->ostate == PREP_HEADER) {
uint8_t *hdptr = ctx->oheader;
memset(ctx->oheader, 0, sizeof(ctx->oheader));
*hdptr |= (iocb->fin << 7) & 0x80u;
*hdptr |= (iocb->rsv << 4) & 0x70u;
*hdptr |= iocb->opcode & 0xfu;
++hdptr;
*hdptr |= (iocb->mask << 7) & 0x80u;
if(wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(iocb->payload_length < 126) {
*hdptr |= iocb->payload_length;
++hdptr;
} else if(iocb->payload_length < (1 << 16)) {
uint16_t len = htons(iocb->payload_length);
*hdptr |= 126;
++hdptr;
memcpy(hdptr, &len, 2);
hdptr += 2;
} else if(iocb->payload_length < (1ull << 63)) {
uint64_t len = hton64(iocb->payload_length);
*hdptr |= 127;
++hdptr;
memcpy(hdptr, &len, 8);
hdptr += 8;
} else {
/* Too large payload length */
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(iocb->mask) {
if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
ctx->user_data) != 0) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->omask = 1;
memcpy(hdptr, ctx->omaskkey, 4);
hdptr += 4;
}
}
ctx->ostate = SEND_HEADER;
ctx->oheadermark = ctx->oheader;
ctx->oheaderlimit = hdptr;
ctx->opayloadlen = iocb->payload_length;
ctx->opayloadoff = 0;
}
if(ctx->ostate == SEND_HEADER) {
ptrdiff_t len = ctx->oheaderlimit-ctx->oheadermark;
ssize_t r;
int flags = 0;
if(iocb->data_length > 0) {
flags |= WSLAY_MSG_MORE;
};
r = ctx->callbacks.send_callback(ctx->oheadermark, len, flags,
ctx->user_data);
if(r > 0) {
if(r > len) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->oheadermark += r;
if(ctx->oheadermark == ctx->oheaderlimit) {
ctx->ostate = SEND_PAYLOAD;
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
if(ctx->ostate == SEND_PAYLOAD) {
size_t totallen = 0;
if(iocb->data_length > 0) {
if(ctx->omask) {
uint8_t temp[4096];
const uint8_t *datamark = iocb->data,
*datalimit = iocb->data+iocb->data_length;
while(datamark < datalimit) {
const uint8_t *writelimit = datamark+
wslay_min(sizeof(temp), datalimit-datamark);
size_t writelen = writelimit-datamark;
ssize_t r;
int i;
for(i = 0; i < writelen; ++i) {
temp[i] = datamark[i]^ctx->omaskkey[(ctx->opayloadoff+i)%4];
}
r = ctx->callbacks.send_callback(temp, writelen, 0, ctx->user_data);
if(r > 0) {
if(r > writelen) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
datamark += r;
ctx->opayloadoff += r;
totallen += r;
}
} else {
if(totallen > 0) {
break;
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
}
} else {
ssize_t r;
r = ctx->callbacks.send_callback(iocb->data, iocb->data_length, 0,
ctx->user_data);
if(r > 0) {
if(r > iocb->data_length) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->opayloadoff += r;
totallen = r;
}
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
}
if(ctx->opayloadoff == ctx->opayloadlen) {
ctx->ostate = PREP_HEADER;
}
return totallen;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}
static void wslay_shift_ibuf(wslay_frame_context_ptr ctx)
{
ptrdiff_t len = ctx->ibuflimit-ctx->ibufmark;
memmove(ctx->ibuf, ctx->ibufmark, len);
ctx->ibuflimit = ctx->ibuf+len;
ctx->ibufmark = ctx->ibuf;
}
static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
{
ssize_t r;
if(ctx->ibufmark != ctx->ibuf) {
wslay_shift_ibuf(ctx);
}
r = ctx->callbacks.recv_callback
(ctx->ibuflimit, ctx->ibuf+sizeof(ctx->ibuf)-ctx->ibuflimit,
0, ctx->user_data);
if(r > 0) {
ctx->ibuflimit += r;
} else {
r = WSLAY_ERR_WANT_READ;
}
return r;
}
#define WSLAY_AVAIL_IBUF(ctx) (ctx->ibuflimit-ctx->ibufmark)
ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb)
{
ssize_t r;
if(ctx->istate == RECV_HEADER1) {
uint8_t fin, opcode, rsv, payloadlen;
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
fin = (ctx->ibufmark[0] >> 7) & 1;
rsv = (ctx->ibufmark[0] >> 4) & 7;
opcode = ctx->ibufmark[0] & 0xfu;
ctx->iom.opcode = opcode;
ctx->iom.fin = fin;
ctx->iom.rsv = rsv;
++ctx->ibufmark;
ctx->imask = (ctx->ibufmark[0] >> 7) & 1;
payloadlen = ctx->ibufmark[0] & 0x7fu;
++ctx->ibufmark;
if(wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
return WSLAY_ERR_PROTO;
}
if(payloadlen == 126) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 2;
} else if(payloadlen == 127) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 8;
} else {
ctx->ipayloadlen = payloadlen;
ctx->ipayloadoff = 0;
if(ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
ctx->istate = RECV_PAYLOAD;
}
}
}
if(ctx->istate == RECV_EXT_PAYLOADLEN) {
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
return r;
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
ctx->ipayloadlen = 0;
ctx->ipayloadoff = 0;
memcpy((uint8_t*)&ctx->ipayloadlen+(8-ctx->ireqread),
ctx->ibufmark, ctx->ireqread);
ctx->ipayloadlen = ntoh64(ctx->ipayloadlen);
ctx->ibufmark += ctx->ireqread;
if(ctx->ireqread == 8) {
if(ctx->ipayloadlen < (1 << 16) ||
ctx->ipayloadlen & (1ull << 63)) {
return WSLAY_ERR_PROTO;
}
} else if(ctx->ipayloadlen < 126) {
return WSLAY_ERR_PROTO;
}
if(ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
ctx->istate = RECV_PAYLOAD;
}
}
if(ctx->istate == RECV_MASKKEY) {
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
return r;
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
memcpy(ctx->imaskkey, ctx->ibufmark, 4);
ctx->ibufmark += 4;
ctx->istate = RECV_PAYLOAD;
}
if(ctx->istate == RECV_PAYLOAD) {
uint8_t *readlimit, *readmark;
uint64_t rempayloadlen = ctx->ipayloadlen-ctx->ipayloadoff;
if(WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
if((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
readmark = ctx->ibufmark;
readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen ?
ctx->ibuflimit : ctx->ibufmark+rempayloadlen;
if(ctx->imask) {
for(; ctx->ibufmark != readlimit;
++ctx->ibufmark, ++ctx->ipayloadoff) {
ctx->ibufmark[0] ^= ctx->imaskkey[ctx->ipayloadoff % 4];
}
} else {
ctx->ibufmark = readlimit;
ctx->ipayloadoff += readlimit-readmark;
}
iocb->fin = ctx->iom.fin;
iocb->rsv = ctx->iom.rsv;
iocb->opcode = ctx->iom.opcode;
iocb->payload_length = ctx->ipayloadlen;
iocb->mask = ctx->imask;
iocb->data = readmark;
iocb->data_length = ctx->ibufmark-readmark;
if(ctx->ipayloadlen == ctx->ipayloadoff) {
ctx->istate = RECV_HEADER1;
ctx->ireqread = 2;
}
return iocb->data_length;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}

76
deps/wslay/lib/wslay_frame.h vendored Normal file
View File

@ -0,0 +1,76 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_FRAME_H
#define WSLAY_FRAME_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <wslay/wslay.h>
enum wslay_frame_state {
PREP_HEADER,
SEND_HEADER,
SEND_PAYLOAD,
RECV_HEADER1,
RECV_PAYLOADLEN,
RECV_EXT_PAYLOADLEN,
RECV_MASKKEY,
RECV_PAYLOAD
};
struct wslay_frame_opcode_memo {
uint8_t fin;
uint8_t opcode;
uint8_t rsv;
};
struct wslay_frame_context {
uint8_t ibuf[4096];
uint8_t *ibufmark;
uint8_t *ibuflimit;
struct wslay_frame_opcode_memo iom;
uint64_t ipayloadlen;
uint64_t ipayloadoff;
uint8_t imask;
uint8_t imaskkey[4];
enum wslay_frame_state istate;
size_t ireqread;
uint8_t oheader[14];
uint8_t *oheadermark;
uint8_t *oheaderlimit;
uint64_t opayloadlen;
uint64_t opayloadoff;
uint8_t omask;
uint8_t omaskkey[4];
enum wslay_frame_state ostate;
struct wslay_frame_callbacks callbacks;
void *user_data;
};
#endif /* WSLAY_FRAME_H */

62
deps/wslay/lib/wslay_net.c vendored Normal file
View File

@ -0,0 +1,62 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_net.h"
#ifndef WORDS_BIGENDIAN
static uint16_t byteswap16(uint16_t x)
{
return ((x & 0xffu) << 8) | (x >> 8);;
}
#ifdef HAVE_NTOHL
# define byteswap32(x) ntohl(x)
#else /* !HAVE_NTOHL */
static uint32_t byteswap32(uint32_t x)
{
uint32_t u = byteswap16(x & 0xffffu);
uint32_t l = byteswap16(x >> 16);
return (u << 16) | l;
}
#endif /* !HAVE_NTOHL */
static uint64_t byteswap64(uint64_t x)
{
uint64_t u = byteswap32(x & 0xffffffffllu);
uint64_t l = byteswap32(x >> 32);
return (u << 32) | l;
}
uint16_t wslay_byteswap16(uint16_t x)
{
return byteswap16(x);
}
uint64_t wslay_byteswap64(uint64_t x)
{
return byteswap64(x);
}
#endif /* !WORDS_BIGENDIAN */

63
deps/wslay/lib/wslay_net.h vendored Normal file
View File

@ -0,0 +1,63 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_NET_H
#define WSLAY_NET_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <wslay/wslay.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#ifdef WORDS_BIGENDIAN
# ifndef HAVE_HTONS
# define htons(x) (x)
# endif /* !HAVE_HTONS */
# ifndef HAVE_NTOHS
# define ntohs(x) (x)
# endif /* !HAVE_NTOHS */
# define ntoh64(x) (x)
# define hton64(x) (x)
#else /* !WORDS_BIGENDIAN */
uint16_t wslay_byteswap16(uint16_t x);
uint64_t wslay_byteswap64(uint64_t x);
# ifndef HAVE_HTONS
# define htons(x) wslay_byteswap16(x)
# endif /* !HAVE_HTONS */
# ifndef HAVE_NTOHS
# define ntohs(x) wslay_byteswap16(x)
# endif /* !HAVE_NTOHS */
# define ntoh64(x) wslay_byteswap64(x)
# define hton64(x) wslay_byteswap64(x)
#endif /* !WORDS_BIGENDIAN */
#endif /* WSLAY_NET_H */

116
deps/wslay/lib/wslay_queue.c vendored Normal file
View File

@ -0,0 +1,116 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_queue.h"
#include <string.h>
#include <assert.h>
struct wslay_queue* wslay_queue_new()
{
struct wslay_queue *queue = (struct wslay_queue*)malloc
(sizeof(struct wslay_queue));
if(!queue) {
return NULL;
}
queue->top = queue->tail = NULL;
return queue;
}
void wslay_queue_free(struct wslay_queue *queue)
{
if(!queue) {
return;
}
struct wslay_queue_cell *p = queue->top;
while(p) {
struct wslay_queue_cell *next = p->next;
free(p);
p = next;
}
free(queue);
}
int wslay_queue_push(struct wslay_queue *queue, void *data)
{
struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
(sizeof(struct wslay_queue_cell));
if(!new_cell) {
return WSLAY_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = NULL;
if(queue->tail) {
queue->tail->next = new_cell;
queue->tail = new_cell;
} else {
queue->top = queue->tail = new_cell;
}
return 0;
}
int wslay_queue_push_front(struct wslay_queue *queue, void *data)
{
struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
(sizeof(struct wslay_queue_cell));
if(!new_cell) {
return WSLAY_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = queue->top;
queue->top = new_cell;
if(!queue->tail) {
queue->tail = queue->top;
}
return 0;
}
void wslay_queue_pop(struct wslay_queue *queue)
{
struct wslay_queue_cell *top = queue->top;
assert(top);
queue->top = top->next;
if(top == queue->tail) {
queue->tail = NULL;
}
free(top);
}
void* wslay_queue_top(struct wslay_queue *queue)
{
assert(queue->top);
return queue->top->data;
}
void* wslay_queue_tail(struct wslay_queue *queue)
{
assert(queue->tail);
return queue->tail->data;
}
int wslay_queue_empty(struct wslay_queue *queue)
{
return queue->top == NULL;
}

53
deps/wslay/lib/wslay_queue.h vendored Normal file
View File

@ -0,0 +1,53 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_QUEUE_H
#define WSLAY_QUEUE_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <wslay/wslay.h>
struct wslay_queue_cell {
void *data;
struct wslay_queue_cell *next;
};
struct wslay_queue {
struct wslay_queue_cell *top;
struct wslay_queue_cell *tail;
};
struct wslay_queue* wslay_queue_new();
void wslay_queue_free(struct wslay_queue *queue);
int wslay_queue_push(struct wslay_queue *queue, void *data);
int wslay_queue_push_front(struct wslay_queue *queue, void *data);
void wslay_queue_pop(struct wslay_queue *queue);
void* wslay_queue_top(struct wslay_queue *queue);
void* wslay_queue_tail(struct wslay_queue *queue);
int wslay_queue_empty(struct wslay_queue *queue);
#endif /* WSLAY_QUEUE_H */

85
deps/wslay/lib/wslay_stack.c vendored Normal file
View File

@ -0,0 +1,85 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_stack.h"
#include <string.h>
#include <assert.h>
struct wslay_stack* wslay_stack_new()
{
struct wslay_stack *stack = (struct wslay_stack*)malloc
(sizeof(struct wslay_stack));
if(!stack) {
return NULL;
}
stack->top = NULL;
return stack;
}
void wslay_stack_free(struct wslay_stack *stack)
{
if(!stack) {
return;
}
struct wslay_stack_cell *p = stack->top;
while(p) {
struct wslay_stack_cell *next = p->next;
free(p);
p = next;
}
free(stack);
}
int wslay_stack_push(struct wslay_stack *stack, void *data)
{
struct wslay_stack_cell *new_cell = (struct wslay_stack_cell*)malloc
(sizeof(struct wslay_stack_cell));
if(!new_cell) {
return WSLAY_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = stack->top;
stack->top = new_cell;
return 0;
}
void wslay_stack_pop(struct wslay_stack *stack)
{
struct wslay_stack_cell *top = stack->top;
assert(top);
stack->top = top->next;
free(top);
}
void* wslay_stack_top(struct wslay_stack *stack)
{
assert(stack->top);
return stack->top->data;
}
int wslay_stack_empty(struct wslay_stack *stack)
{
return stack->top == NULL;
}

50
deps/wslay/lib/wslay_stack.h vendored Normal file
View File

@ -0,0 +1,50 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_STACK_H
#define WSLAY_STACK_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <wslay/wslay.h>
struct wslay_stack_cell {
void *data;
struct wslay_stack_cell *next;
};
struct wslay_stack {
struct wslay_stack_cell *top;
};
struct wslay_stack* wslay_stack_new();
void wslay_stack_free(struct wslay_stack *stack);
int wslay_stack_push(struct wslay_stack *stack, void *data);
void wslay_stack_pop(struct wslay_stack *stack);
void* wslay_stack_top(struct wslay_stack *stack);
int wslay_stack_empty(struct wslay_stack *stack);
#endif /* WSLAY_STACK_H */

1
deps/wslay/m4/README vendored Normal file
View File

@ -0,0 +1 @@
Empty m4 directory to make `autoreconf -i` happy.

44
deps/wslay/tests/Makefile.am vendored Normal file
View File

@ -0,0 +1,44 @@
# Wslay - The WebSocket Library
# Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if HAVE_CUNIT
check_PROGRAMS = main
OBJECTS = main.c wslay_frame_test.c\
wslay_event_test.c\
wslay_queue_test.c
HFILES = wslay_session_test.h wslay_frame_test.h\
wslay_event_test.h\
wslay_queue_test.h
main_SOURCES = $(HFILES) $(OBJECTS)
main_LDADD = ${top_builddir}/lib/libwslay.la -lcunit
main_LDFLAGS = -static
AM_CFLAGS = -Wall -g -O2 -I${top_srcdir}/lib -I${top_srcdir}/lib/includes
# DEFS += -D_ISOC99_SOURCE -D_GNU_SOURCE
TESTS = main
endif # HAVE_CUNIT

126
deps/wslay/tests/main.c vendored Normal file
View File

@ -0,0 +1,126 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <CUnit/Basic.h>
/* include test cases' include files here */
#include "wslay_frame_test.h"
#include "wslay_event_test.h"
#include "wslay_queue_test.h"
int init_suite1(void)
{
return 0;
}
int clean_suite1(void)
{
return 0;
}
int main()
{
CU_pSuite pSuite = NULL;
/* 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 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",
test_wslay_frame_recv_1byte) ||
!CU_add_test(pSuite, "wslay_frame_recv_fragmented",
test_wslay_frame_recv_fragmented) ||
!CU_add_test(pSuite, "wslay_frame_recv_interleaved_ctrl_frame",
test_wslay_frame_recv_interleaved_ctrl_frame) ||
!CU_add_test(pSuite, "wslay_frame_recv_zero_payloadlen",
test_wslay_frame_recv_zero_payloadlen) ||
!CU_add_test(pSuite, "wslay_frame_recv_too_large_payload",
test_wslay_frame_recv_too_large_payload) ||
!CU_add_test(pSuite, "wslay_frame_recv_ctrl_too_large_payload",
test_wslay_frame_recv_ctrl_frame_too_large_payload) ||
!CU_add_test(pSuite, "wslay_frame_recv_minimum_ext_payload16",
test_wslay_frame_recv_minimum_ext_payload16) ||
!CU_add_test(pSuite, "wslay_frame_recv_minimum_ext_payload64",
test_wslay_frame_recv_minimum_ext_payload64) ||
!CU_add_test(pSuite, "wslay_frame_send", test_wslay_frame_send) ||
!CU_add_test(pSuite, "wslay_frame_send_fragmented",
test_wslay_frame_send_fragmented) ||
!CU_add_test(pSuite, "wslay_frame_send_interleaved_ctrl_frame",
test_wslay_frame_send_interleaved_ctrl_frame) ||
!CU_add_test(pSuite, "wslay_frame_send_1byte_masked",
test_wslay_frame_send_1byte_masked) ||
!CU_add_test(pSuite, "wslay_frame_send_zero_payloadlen",
test_wslay_frame_send_zero_payloadlen) ||
!CU_add_test(pSuite, "wslay_frame_send_too_large_payload",
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_event_send_fragmented_msg",
test_wslay_event_send_fragmented_msg) ||
!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_ctrl_msg_first",
test_wslay_event_send_ctrl_msg_first) ||
!CU_add_test(pSuite, "wslay_event_queue_close",
test_wslay_event_queue_close) ||
!CU_add_test(pSuite, "wslay_event_queue_close_without_code",
test_wslay_event_queue_close_without_code) ||
!CU_add_test(pSuite, "wslay_event_recv_close_without_code",
test_wslay_event_recv_close_without_code) ||
!CU_add_test(pSuite, "wslay_event_reply_close",
test_wslay_event_reply_close) ||
!CU_add_test(pSuite, "wslay_event_no_more_msg",
test_wslay_event_no_more_msg) ||
!CU_add_test(pSuite, "wslay_event_callback_failure",
test_wslay_event_callback_failure) ||
!CU_add_test(pSuite, "wslay_event_no_buffering",
test_wslay_event_no_buffering) ||
!CU_add_test(pSuite, "wslay_event_frame_too_big",
test_wslay_event_frame_too_big) ||
!CU_add_test(pSuite, "wslay_event_message_too_big",
test_wslay_event_message_too_big) ||
!CU_add_test(pSuite, "wslay_queue", test_wslay_queue)) {
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();
CU_cleanup_registry();
return CU_get_error();
}

491
deps/wslay/tests/wslay_event_test.c vendored Normal file
View File

@ -0,0 +1,491 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_event_test.h"
#include <assert.h>
#include <CUnit/CUnit.h>
#include "wslay_event.h"
struct scripted_data_feed {
uint8_t data[8192];
uint8_t* datamark;
uint8_t* datalimit;
size_t feedseq[8192];
size_t seqidx;
};
struct accumulator {
uint8_t buf[4096];
size_t length;
};
struct my_user_data {
struct scripted_data_feed *df;
struct accumulator *acc;
};
static void scripted_data_feed_init(struct scripted_data_feed *df,
const uint8_t *data, size_t data_length)
{
memset(df, 0, sizeof(struct scripted_data_feed));
memcpy(df->data, data, data_length);
df->datamark = df->data;
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;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
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;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
return wlen;
}
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);
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;
assert(len > 0);
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)
{
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)
{
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
void test_wslay_event_send_fragmented_msg()
{
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
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);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
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(9, 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()
{
int i;
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
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" */
};
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 = one_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(1 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(0 == wslay_event_get_queued_msg_length(ctx));
CU_ASSERT(0 == wslay_event_send(ctx));
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));
for(i = 0; i < 10; ++i) {
CU_ASSERT(0 == wslay_event_send(ctx));
}
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(11 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
wslay_event_context_free(ctx);
}
void test_wslay_event_send_ctrl_msg_first()
{
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
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" */
};
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_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(0 == wslay_event_send(ctx));
CU_ASSERT(9 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
wslay_event_context_free(ctx);
}
void test_wslay_event_queue_close()
{
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" */
};
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);
CU_ASSERT(0 == wslay_event_queue_close(ctx, WSLAY_CODE_MESSAGE_TOO_BIG,
(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));
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_queue_close_without_code()
{
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 };
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);
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &ping));
// See that ping is not sent because close frame is queued
CU_ASSERT(0 == wslay_event_queue_close(ctx, 0, NULL, 0));
CU_ASSERT(0 == wslay_event_send(ctx));
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));
wslay_event_context_free(ctx);
}
void test_wslay_event_recv_close_without_code()
{
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
const uint8_t msg[] = { 0x88u, 0x00 };
struct scripted_data_feed df;
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;
wslay_event_context_client_init(&ctx, &callbacks, &ud);
CU_ASSERT(0 == wslay_event_recv(ctx));
CU_ASSERT(1 == wslay_event_get_close_received(ctx));
CU_ASSERT(WSLAY_CODE_NO_STATUS_RCVD ==
wslay_event_get_status_code_received(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_reply_close()
{
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 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));
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.recv_callback = scripted_recv_callback;
memset(&acc, 0, sizeof(acc));
ud.df = &df;
ud.acc = &acc;
wslay_event_context_server_init(&ctx, &callbacks, &ud);
CU_ASSERT(0 == wslay_event_recv(ctx));
CU_ASSERT(1 == wslay_event_get_queued_msg_count(ctx));
/* 7 bytes = 2 bytes status code + "Hello" */
CU_ASSERT(7 == wslay_event_get_queued_msg_length(ctx));
CU_ASSERT(1 == wslay_event_get_close_received(ctx));
CU_ASSERT(WSLAY_CODE_MESSAGE_TOO_BIG ==
wslay_event_get_status_code_received(ctx));
CU_ASSERT(WSLAY_CODE_ABNORMAL_CLOSURE ==
wslay_event_get_status_code_sent(ctx));
CU_ASSERT(0 == wslay_event_send(ctx));
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(0 == wslay_event_get_queued_msg_length(ctx));
CU_ASSERT(9 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
CU_ASSERT(WSLAY_CODE_MESSAGE_TOO_BIG ==
wslay_event_get_status_code_received(ctx));
CU_ASSERT(WSLAY_CODE_MESSAGE_TOO_BIG ==
wslay_event_get_status_code_sent(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_no_more_msg()
{
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
wslay_event_context_server_init(&ctx, &callbacks, NULL);
CU_ASSERT(0 == wslay_event_queue_close(ctx, 0, NULL, 0));
CU_ASSERT(WSLAY_ERR_NO_MORE_MSG == wslay_event_queue_close(ctx, 0, NULL, 0));
wslay_event_context_free(ctx);
}
void test_wslay_event_callback_failure()
{
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.recv_callback = fail_recv_callback;
callbacks.send_callback = fail_send_callback;
wslay_event_context_server_init(&ctx, &callbacks, NULL);
CU_ASSERT(WSLAY_ERR_CALLBACK_FAILURE == wslay_event_recv(ctx));
/* close control frame is in queue */
CU_ASSERT(WSLAY_ERR_CALLBACK_FAILURE == wslay_event_send(ctx));
wslay_event_context_free(ctx);
}
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) {
CU_ASSERT(3 == arg->msg_length);
CU_ASSERT(0 == memcmp("Foo", arg->msg, arg->msg_length));
} else {
CU_ASSERT(WSLAY_TEXT_FRAME == arg->opcode);
CU_ASSERT(0 == arg->msg_length);
}
}
void test_wslay_event_no_buffering()
{
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" */
};
struct scripted_data_feed df;
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;
callbacks.on_msg_recv_callback = no_buffering_callback;
wslay_event_context_client_init(&ctx, &callbacks, &ud);
wslay_event_config_set_no_buffering(ctx, 1);
CU_ASSERT(0 == wslay_event_recv(ctx));
/* pong must be queued */
CU_ASSERT(wslay_event_want_write(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_frame_too_big()
{
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 ans[] = { 0x88, 0x02,
0x03, 0xf1 /* 1009 */
};
struct scripted_data_feed df;
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;
memset(&acc, 0, sizeof(acc));
ud.df = &df;
ud.acc = &acc;
wslay_event_context_server_init(&ctx, &callbacks, &ud);
wslay_event_config_set_max_recv_msg_length(ctx, 4);
CU_ASSERT(0 == wslay_event_recv(ctx));
CU_ASSERT(0 == wslay_event_send(ctx));
CU_ASSERT(4 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
CU_ASSERT(WSLAY_CODE_MESSAGE_TOO_BIG ==
wslay_event_get_status_code_sent(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_message_too_big()
{
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 ans[] = { 0x88, 0x02,
0x03, 0xf1 /* 1009 */
};
struct scripted_data_feed df;
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;
memset(&acc, 0, sizeof(acc));
ud.df = &df;
ud.acc = &acc;
wslay_event_context_server_init(&ctx, &callbacks, &ud);
wslay_event_config_set_max_recv_msg_length(ctx, 9);
CU_ASSERT(0 == wslay_event_recv(ctx));
CU_ASSERT(0 == wslay_event_send(ctx));
CU_ASSERT(4 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
CU_ASSERT(WSLAY_CODE_MESSAGE_TOO_BIG ==
wslay_event_get_status_code_sent(ctx));
wslay_event_context_free(ctx);
}

41
deps/wslay/tests/wslay_event_test.h vendored Normal file
View File

@ -0,0 +1,41 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_EVENT_TEST_H
#define WSLAY_EVENT_TEST_H
void test_wslay_event_send_fragmented_msg();
void test_wslay_event_send_fragmented_msg_with_ctrl();
void test_wslay_event_send_ctrl_msg_first();
void test_wslay_event_queue_close();
void test_wslay_event_queue_close_without_code();
void test_wslay_event_recv_close_without_code();
void test_wslay_event_reply_close();
void test_wslay_event_no_more_msg();
void test_wslay_event_callback_failure();
void test_wslay_event_no_buffering();
void test_wslay_event_frame_too_big();
void test_wslay_event_message_too_big();
#endif // WSLAY_EVENT_TEST_H

560
deps/wslay/tests/wslay_frame_test.c vendored Normal file
View File

@ -0,0 +1,560 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_frame_test.h"
#include <assert.h>
#include <CUnit/CUnit.h>
#include "wslay_frame.h"
void test_wslay_frame_context_init()
{
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
int user_data;
CU_ASSERT_FALSE(wslay_frame_context_init(&ctx, &callbacks, &user_data));
wslay_frame_context_free(ctx);
}
struct scripted_data_feed {
uint8_t data[8192];
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)
{
memset(df, 0, sizeof(struct scripted_data_feed));
memcpy(df->data, data, data_length);
df->datamark = df->data;
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;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
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;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(df->datamark, data, wlen);
df->datamark += wlen;
if(wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
return wlen;
}
void test_wslay_frame_recv()
{
wslay_frame_context_ptr ctx;
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 };
scripted_data_feed_init(&df, msg, sizeof(msg));
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT(5 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(0x1, iocb.opcode);
CU_ASSERT_EQUAL(5, iocb.payload_length);
CU_ASSERT_EQUAL(1, iocb.mask);
CU_ASSERT_EQUAL(5, iocb.data_length);
CU_ASSERT(memcmp("Hello", iocb.data, iocb.data_length) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_1byte()
{
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
int i;
/* Masked text frame containing "Hello" */
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) {
df.feedseq[i] = 1;
}
wslay_frame_context_init(&ctx, &callbacks, &df);
for(i = 0; i < 4; ++i) {
CU_ASSERT(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
}
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);
CU_ASSERT_EQUAL(0x1, iocb.opcode);
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(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_fragmented()
{
wslay_frame_context_ptr ctx;
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" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 5;
df.feedseq[1] = 4;
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT(3 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(0, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_TEXT_FRAME, iocb.opcode);
CU_ASSERT_EQUAL(3, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(3, iocb.data_length);
CU_ASSERT(memcmp("Hel", iocb.data, iocb.data_length) == 0);
CU_ASSERT(2 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_CONTINUATION_FRAME, iocb.opcode);
CU_ASSERT_EQUAL(2, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(2, iocb.data_length);
CU_ASSERT(memcmp("lo", iocb.data, iocb.data_length) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_interleaved_ctrl_frame()
{
wslay_frame_context_ptr ctx;
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" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 5;
df.feedseq[1] = 7,
df.feedseq[2] = 4;
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT(3 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(0, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_TEXT_FRAME, iocb.opcode);
CU_ASSERT_EQUAL(3, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(3, iocb.data_length);
CU_ASSERT(memcmp("Hel", iocb.data, iocb.data_length) == 0);
CU_ASSERT(5 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_PING, iocb.opcode);
CU_ASSERT_EQUAL(5, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(5, iocb.data_length);
CU_ASSERT(memcmp("Hello", iocb.data, iocb.data_length) == 0);
CU_ASSERT(2 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_CONTINUATION_FRAME, iocb.opcode);
CU_ASSERT_EQUAL(2, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(2, iocb.data_length);
CU_ASSERT(memcmp("lo", iocb.data, iocb.data_length) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_zero_payloadlen()
{
wslay_frame_context_ptr ctx;
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 }; /* "" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 2;
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT(0 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
CU_ASSERT_EQUAL(WSLAY_TEXT_FRAME, iocb.opcode);
CU_ASSERT_EQUAL(0, iocb.payload_length);
CU_ASSERT_EQUAL(0, iocb.mask);
CU_ASSERT_EQUAL(0, iocb.data_length);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_too_large_payload()
{
wslay_frame_context_ptr ctx;
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};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT_EQUAL(WSLAY_ERR_PROTO, wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_ctrl_frame_too_large_payload()
{
wslay_frame_context_ptr ctx;
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 };
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT_EQUAL(WSLAY_ERR_PROTO, wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_minimum_ext_payload16()
{
wslay_frame_context_ptr ctx;
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 };
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT_EQUAL(WSLAY_ERR_PROTO, wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_minimum_ext_payload64()
{
wslay_frame_context_ptr ctx;
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};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT_EQUAL(WSLAY_ERR_PROTO, wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
struct accumulator {
uint8_t buf[4096];
size_t length;
};
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);
acc->length += len;
return len;
}
static int static_genmask_callback(uint8_t *buf, size_t len,
void* user_data)
{
const static uint8_t makskey[] = { 0x37u, 0xfau, 0x21u, 0x3du };
memcpy(buf, makskey, 4);
return 0;
}
void test_wslay_frame_send()
{
wslay_frame_context_ptr ctx;
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 };
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
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(5 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg), acc.length);
CU_ASSERT(memcmp(msg, acc.buf, sizeof(msg)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_fragmented()
{
wslay_frame_context_ptr ctx;
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" */
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
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(3 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
CU_ASSERT(memcmp(msg1, acc.buf, sizeof(msg1)) == 0);
acc.length = 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(2 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg2), acc.length);
CU_ASSERT(memcmp(msg2, acc.buf, sizeof(msg2)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_interleaved_ctrl_frame()
{
wslay_frame_context_ptr ctx;
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 };
/* 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 };
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
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(3 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
CU_ASSERT(memcmp(msg1, acc.buf, sizeof(msg1)) == 0);
acc.length = 0;
iocb.fin = 1;
iocb.opcode = WSLAY_PING;
iocb.payload_length = 5;
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);
CU_ASSERT(memcmp(msg2, acc.buf, sizeof(msg2)) == 0);
acc.length = 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(2 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg3), acc.length);
CU_ASSERT(memcmp(msg3, acc.buf, sizeof(msg3)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_1byte_masked()
{
wslay_frame_context_ptr ctx;
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 hello[] = "Hello";
struct scripted_data_feed df;
int i;
scripted_data_feed_init(&df, NULL, 0);
for(i = 0; i < sizeof(msg); ++i) {
df.feedseq[i] = 1;
}
wslay_frame_context_init(&ctx, &callbacks, &df);
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;
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));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_zero_payloadlen()
{
wslay_frame_context_ptr ctx;
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 }; /* "" */
acc.length = 0;
wslay_frame_context_init(&ctx, &callbacks, &acc);
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(0 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg), acc.length);
CU_ASSERT(memcmp(msg, acc.buf, sizeof(msg)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_too_large_payload()
{
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
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_send(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_ctrl_frame_too_large_payload()
{
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
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_send(ctx, &iocb));
wslay_frame_context_free(ctx);
}

46
deps/wslay/tests/wslay_frame_test.h vendored Normal file
View File

@ -0,0 +1,46 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_FRAME_TEST_H
#define WSLAY_FRAME_TEST_H
void test_wslay_frame_context_init();
void test_wslay_frame_recv();
void test_wslay_frame_recv_1byte();
void test_wslay_frame_recv_fragmented();
void test_wslay_frame_recv_interleaved_ctrl_frame();
void test_wslay_frame_recv_zero_payloadlen();
void test_wslay_frame_recv_too_large_payload();
void test_wslay_frame_recv_ctrl_frame_too_large_payload();
void test_wslay_frame_recv_minimum_ext_payload16();
void test_wslay_frame_recv_minimum_ext_payload64();
void test_wslay_frame_send();
void test_wslay_frame_send_fragmented();
void test_wslay_frame_send_interleaved_ctrl_frame();
void test_wslay_frame_send_1byte_masked();
void test_wslay_frame_send_zero_payloadlen();
void test_wslay_frame_send_too_large_payload();
void test_wslay_frame_send_ctrl_frame_too_large_payload();
#endif // WSLAY_FRAME_TEST_H

59
deps/wslay/tests/wslay_queue_test.c vendored Normal file
View File

@ -0,0 +1,59 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_queue_test.h"
#include <CUnit/CUnit.h>
#include "wslay_queue.h"
void test_wslay_queue()
{
int ints[] = { 1, 2, 3, 4, 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));
}
for(i = 0; i < 5; ++i) {
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
wslay_queue_pop(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 = 4; i >= 0; --i) {
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
wslay_queue_pop(queue);
}
CU_ASSERT(wslay_queue_empty(queue));
wslay_queue_free(queue);
}

30
deps/wslay/tests/wslay_queue_test.h vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_QUEUE_TEST_H
#define WSLAY_QUEUE_TEST_H
void test_wslay_queue();
#endif // WSLAY_QUEUE_TEST_H

27
deps/wslay/tests/wslay_session_test.c vendored Normal file
View File

@ -0,0 +1,27 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_session_test.h"
#include <CUnit/CUnit.h>

28
deps/wslay/tests/wslay_session_test.h vendored Normal file
View File

@ -0,0 +1,28 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_SESSION_TEST_H
#define WSLAY_SESSION_TEST_H
#endif // WSLAY_SESSION_TEST_H

48
deps/wslay/tests/wslay_stack_test.c vendored Normal file
View File

@ -0,0 +1,48 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "wslay_stack_test.h"
#include <CUnit/CUnit.h>
#include "wslay_stack.h"
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) {
wslay_stack_push(stack, &ints[i]);
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)));
wslay_stack_pop(stack);
}
CU_ASSERT(wslay_stack_empty(stack));
wslay_stack_free(stack);
}

30
deps/wslay/tests/wslay_stack_test.h vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Wslay - The WebSocket Library
*
* Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WSLAY_STACK_TEST_H
#define WSLAY_STACK_TEST_H
void test_wslay_stack();
#endif // WSLAY_STACK_TEST_H