Update wslay

This commit is contained in:
Tatsuhiro Tsujikawa 2021-08-12 23:47:06 +09:00
parent a151b5bcef
commit 63f6ed726e
23 changed files with 2092 additions and 1613 deletions

85
deps/wslay/NEWS vendored
View File

@ -1,47 +1,82 @@
wslay 1.0.0
wslay 1.1.1
===========
Release Note
------------
This release fixes several build issues. Most changes were introduced
by contributors. Thank you for all the contributions in this project.
Because wslay is very stable since the previous release (more than 2
years ago), we mark this release 1.0.0.
This release fixes the bug that eof is not evaluated after the
invocation of read_callback.
Changes
-------
* Fix NULL check in wslay_frame_context_init.
* Check for eof when read_callback returns 0 (GH-47)
Patch from Witchakorn Kamolpornwijit
Patch from Robert Bragg
* the examples uses epoll and thus only be built on linux
Patch from Kazuho Oku
wslay 1.1.0
===========
* build: allow one to build out-of-tree documentation
Release Note
------------
Patch from Vincent Bernat
This release adds CMake build support and the ability to set and
verify reserved bits. Build issue with nettle >= 3.4 was fixed.
* build: fix `./configure` when nettle is not present
Changes
-------
`PKG_CHECK_MODULES` will fail unless we give it an action to execute
on failure. When nettle is not available, we set `have_nettle` to
`no`.
* Fix compilation of examples
Patch from Vincent Bernat
Since 3.4 nettle defines base64_encode_raw like this:
* Adds the ability to override the version header include with a
define. This enables projects to set the build version from the
compile environment and avoid the need to generate the version
header.
void base64_encode_raw(char *dst, size_t length, const uint8_t *src);
Patch from Ben Vanik
So examples have to be adjusted. More read at
https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.4_release_20171119/NEWS#L49-53
* Improve http_handshake in fork-echoserver.
Patch from Sergey Avseyev
Patch from Gurjeet Singh
* check for 0 length before memcpy:
* Don't send any pending control frame other than Close control frame
after Close is queued.
.../wslay/lib/wslay_event.c:304:7: runtime error: null pointer passed as argument 2, which is declared to never be null
Patch from Anders Bakken
* Skip UTF-8 validation for PMCE fragments
If the message was marked with rsv1 on the initial frame then we
should skip utf-8 validation on subsequent continuation frames as
well.
Added test for this case.
Found by autobahn wstest tool.
Patch from Isaac Boukris
* Allow RSV1 bit in event-based API for PMCE - RFC 7692
Add a new function wslay_event_set_allowed_rsv_bits which only accpet
RSV1 for now (or 0 to disable).
Skip UTF-8 validation on frames with RSV1 set as it is too early for that.
Add extended versions of wslay_event_queue_msg functions which also
take the reserved bits to set for this message.
Patch from Isaac Boukris
* fixed missing malloc guard
Patch from Jakub Piskorz
* Fix argc check.
Patch from Anders Bakken
* CMake support
Patch from wonder-mice

View File

@ -1,7 +1,7 @@
Wslay - The WebSocket library
=============================
Project Web: https://github.com/tatsuhiro-t/wslay
Project Web: https://tatsuhiro-t.github.io/wslay/
Wslay is a WebSocket library written in C.
It implements the protocol version 13 described in

View File

@ -21,15 +21,15 @@ dnl LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AC_PREREQ(2.61)
AC_INIT([wslay], [1.0.1-DEV], [t-tujikawa@users.sourceforge.net])
AC_INIT([wslay], [1.1.1], [t-tujikawa@users.sourceforge.net])
LT_PREREQ([2.2.6])
LT_INIT()
AC_CONFIG_AUX_DIR([.])
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 0)
AC_SUBST(LT_CURRENT, 1)
AC_SUBST(LT_REVISION, 1)
AC_SUBST(LT_AGE, 0)
AC_SUBST(LT_AGE, 1)
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
@ -40,6 +40,14 @@ AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE()
AC_CONFIG_HEADERS([config.h])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# Checks for command-line options
AC_ARG_ENABLE([werror],
[AS_HELP_STRING([--enable-werror],
[Turn on compile time warnings])],
[werror=$enableval], [werror=no])
dnl Checks for programs
AC_PROG_CC
AC_PROG_CXX

View File

@ -53,8 +53,7 @@
#include <nettle/sha.h>
#include <wslay/wslay.h>
int create_listen_socket(const char *service)
{
int create_listen_socket(const char *service) {
struct addrinfo hints;
int sfd = -1;
int r;
@ -64,27 +63,27 @@ int create_listen_socket(const char *service)
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
struct addrinfo *res;
r = getaddrinfo(0, service, &hints, &res);
if(r != 0) {
if (r != 0) {
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
return -1;
}
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sfd == -1) {
if (sfd == -1) {
continue;
}
int val = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
continue;
}
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
break;
}
close(sfd);
}
freeaddrinfo(res);
if(listen(sfd, 16) == -1) {
if (listen(sfd, 16) == -1) {
perror("listen");
close(sfd);
return -1;
@ -92,46 +91,45 @@ int create_listen_socket(const char *service)
return sfd;
}
int make_non_block(int fd)
{
int make_non_block(int fd) {
int flags, r;
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
if(flags == -1) {
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
;
if (flags == -1) {
return -1;
}
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
;
if (r == -1) {
return -1;
}
return 0;
}
std::string sha1(const std::string& src)
{
std::string sha1(const std::string &src) {
sha1_ctx ctx;
sha1_init(&ctx);
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t *>(src.c_str()));
uint8_t temp[SHA1_DIGEST_SIZE];
sha1_digest(&ctx, SHA1_DIGEST_SIZE, temp);
std::string res(&temp[0], &temp[SHA1_DIGEST_SIZE]);
return res;
}
std::string base64(const std::string& src)
{
std::string base64(const std::string &src) {
base64_encode_ctx ctx;
base64_encode_init(&ctx);
int dstlen = BASE64_ENCODE_RAW_LENGTH(src.size());
uint8_t *dst = new uint8_t[dstlen];
base64_encode_raw(dst, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
char *dst = new char[dstlen];
base64_encode_raw(dst, src.size(),
reinterpret_cast<const uint8_t *>(src.c_str()));
std::string res(&dst[0], &dst[dstlen]);
delete [] dst;
delete[] dst;
return res;
}
std::string create_acceptkey(const std::string& clientkey)
{
std::string s = clientkey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string create_acceptkey(const std::string &clientkey) {
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
return base64(sha1(s));
}
@ -144,12 +142,11 @@ public:
virtual bool want_write() = 0;
virtual int fd() const = 0;
virtual bool finish() = 0;
virtual EventHandler* next() = 0;
virtual EventHandler *next() = 0;
};
ssize_t send_callback(wslay_event_context_ptr ctx,
const uint8_t *data, size_t len, int flags,
void *user_data);
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
size_t len, int flags, void *user_data);
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
int flags, void *user_data);
void on_msg_recv_callback(wslay_event_context_ptr ctx,
@ -158,93 +155,71 @@ void on_msg_recv_callback(wslay_event_context_ptr ctx,
class EchoWebSocketHandler : public EventHandler {
public:
EchoWebSocketHandler(int fd)
: fd_(fd)
{
EchoWebSocketHandler(int fd) : fd_(fd) {
struct wslay_event_callbacks callbacks = {
recv_callback,
send_callback,
NULL, /* genmask_callback */
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
on_msg_recv_callback
};
recv_callback,
send_callback,
NULL, /* genmask_callback */
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
on_msg_recv_callback};
wslay_event_context_server_init(&ctx_, &callbacks, this);
}
virtual ~EchoWebSocketHandler()
{
virtual ~EchoWebSocketHandler() {
wslay_event_context_free(ctx_);
shutdown(fd_, SHUT_WR);
close(fd_);
}
virtual int on_read_event()
{
if(wslay_event_recv(ctx_) == 0) {
virtual int on_read_event() {
if (wslay_event_recv(ctx_) == 0) {
return 0;
} else {
return -1;
}
}
virtual int on_write_event()
{
if(wslay_event_send(ctx_) == 0) {
virtual int on_write_event() {
if (wslay_event_send(ctx_) == 0) {
return 0;
} else {
return -1;
}
}
ssize_t send_data(const uint8_t *data, size_t len, int flags)
{
ssize_t send_data(const uint8_t *data, size_t len, int flags) {
ssize_t r;
int sflags = 0;
#ifdef MSG_MORE
if(flags & WSLAY_MSG_MORE) {
if (flags & WSLAY_MSG_MORE) {
sflags |= MSG_MORE;
}
#endif // MSG_MORE
while((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR);
while ((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR)
;
return r;
}
ssize_t recv_data(uint8_t *data, size_t len, int flags)
{
ssize_t recv_data(uint8_t *data, size_t len, int flags) {
ssize_t r;
while((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR);
while ((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR)
;
return r;
}
virtual bool want_read()
{
return wslay_event_want_read(ctx_);
}
virtual bool want_write()
{
return wslay_event_want_write(ctx_);
}
virtual int fd() const
{
return fd_;
}
virtual bool finish()
{
return !want_read() && !want_write();
}
virtual EventHandler* next()
{
return 0;
}
virtual bool want_read() { return wslay_event_want_read(ctx_); }
virtual bool want_write() { return wslay_event_want_write(ctx_); }
virtual int fd() const { return fd_; }
virtual bool finish() { return !want_read() && !want_write(); }
virtual EventHandler *next() { return 0; }
private:
int fd_;
wslay_event_context_ptr ctx_;
};
ssize_t send_callback(wslay_event_context_ptr ctx,
const uint8_t *data, size_t len, int flags,
void *user_data)
{
EchoWebSocketHandler *sv = (EchoWebSocketHandler*)user_data;
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
size_t len, int flags, void *user_data) {
EchoWebSocketHandler *sv = (EchoWebSocketHandler *)user_data;
ssize_t r = sv->send_data(data, len, flags);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
@ -254,17 +229,16 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
}
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
int flags, void *user_data)
{
EchoWebSocketHandler *sv = (EchoWebSocketHandler*)user_data;
int flags, void *user_data) {
EchoWebSocketHandler *sv = (EchoWebSocketHandler *)user_data;
ssize_t r = sv->recv_data(data, len, flags);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
}
} else if(r == 0) {
} else if (r == 0) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
r = -1;
}
@ -273,50 +247,44 @@ ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
void on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
if(!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {
arg->opcode, arg->msg, arg->msg_length
};
void *user_data) {
if (!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
wslay_event_queue_msg(ctx, &msgarg);
}
}
class HttpHandshakeSendHandler : public EventHandler {
public:
HttpHandshakeSendHandler(int fd, const std::string& accept_key)
: fd_(fd),
resheaders_("HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: "+accept_key+"\r\n"
"\r\n"),
off_(0)
{}
virtual ~HttpHandshakeSendHandler()
{
if(fd_ != -1) {
HttpHandshakeSendHandler(int fd, const std::string &accept_key)
: fd_(fd),
resheaders_("HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: " +
accept_key +
"\r\n"
"\r\n"),
off_(0) {}
virtual ~HttpHandshakeSendHandler() {
if (fd_ != -1) {
shutdown(fd_, SHUT_WR);
close(fd_);
}
}
virtual int on_read_event()
{
return 0;
}
virtual int on_write_event()
{
while(1) {
size_t len = resheaders_.size()-off_;
if(len == 0) {
virtual int on_read_event() { return 0; }
virtual int on_write_event() {
while (1) {
size_t len = resheaders_.size() - off_;
if (len == 0) {
break;
}
ssize_t r;
while((r = write(fd_, resheaders_.c_str()+off_, len)) == -1 &&
errno == EINTR);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
while ((r = write(fd_, resheaders_.c_str() + off_, len)) == -1 &&
errno == EINTR)
;
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else {
perror("write");
@ -328,25 +296,12 @@ public:
}
return 0;
}
virtual bool want_read()
{
return false;
}
virtual bool want_write()
{
return true;
}
virtual int fd() const
{
return fd_;
}
virtual bool finish()
{
return off_ == resheaders_.size();
}
virtual EventHandler* next()
{
if(finish()) {
virtual bool want_read() { return false; }
virtual bool want_write() { return true; }
virtual int fd() const { return fd_; }
virtual bool finish() { return off_ == resheaders_.size(); }
virtual EventHandler *next() {
if (finish()) {
int fd = fd_;
fd_ = -1;
return new EchoWebSocketHandler(fd);
@ -354,6 +309,7 @@ public:
return 0;
}
}
private:
int fd_;
std::string headers_;
@ -363,79 +319,60 @@ private:
class HttpHandshakeRecvHandler : public EventHandler {
public:
HttpHandshakeRecvHandler(int fd)
: fd_(fd)
{}
virtual ~HttpHandshakeRecvHandler()
{
if(fd_ != -1) {
HttpHandshakeRecvHandler(int fd) : fd_(fd) {}
virtual ~HttpHandshakeRecvHandler() {
if (fd_ != -1) {
close(fd_);
}
}
virtual int on_read_event()
{
virtual int on_read_event() {
char buf[4096];
ssize_t r;
std::string client_key;
while(1) {
while((r = read(fd_, buf, sizeof(buf))) == -1 && errno == EINTR);
if(r == -1) {
if(errno == EWOULDBLOCK || errno == EAGAIN) {
while (1) {
while ((r = read(fd_, buf, sizeof(buf))) == -1 && errno == EINTR)
;
if (r == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
break;
} else {
perror("read");
return -1;
}
} else if(r == 0) {
} else if (r == 0) {
std::cerr << "http_upgrade: Got EOF" << std::endl;
return -1;
} else {
headers_.append(buf, buf+r);
if(headers_.size() > 8192) {
headers_.append(buf, buf + r);
if (headers_.size() > 8192) {
std::cerr << "Too large http header" << std::endl;
return -1;
}
}
}
if(headers_.find("\r\n\r\n") != std::string::npos) {
if (headers_.find("\r\n\r\n") != std::string::npos) {
std::string::size_type keyhdstart;
if(headers_.find("Upgrade: websocket\r\n") == std::string::npos ||
headers_.find("Connection: Upgrade\r\n") == std::string::npos ||
(keyhdstart = headers_.find("Sec-WebSocket-Key: ")) ==
std::string::npos) {
if (headers_.find("Upgrade: websocket\r\n") == std::string::npos ||
headers_.find("Connection: Upgrade\r\n") == std::string::npos ||
(keyhdstart = headers_.find("Sec-WebSocket-Key: ")) ==
std::string::npos) {
std::cerr << "http_upgrade: missing required headers" << std::endl;
return -1;
}
keyhdstart += 19;
std::string::size_type keyhdend = headers_.find("\r\n", keyhdstart);
client_key = headers_.substr(keyhdstart, keyhdend-keyhdstart);
client_key = headers_.substr(keyhdstart, keyhdend - keyhdstart);
accept_key_ = create_acceptkey(client_key);
}
return 0;
}
virtual int on_write_event()
{
return 0;
}
virtual bool want_read()
{
return true;
}
virtual bool want_write()
{
return false;
}
virtual int fd() const
{
return fd_;
}
virtual bool finish()
{
return !accept_key_.empty();
}
virtual EventHandler* next()
{
if(finish()) {
virtual int on_write_event() { return 0; }
virtual bool want_read() { return true; }
virtual bool want_write() { return false; }
virtual int fd() const { return fd_; }
virtual bool finish() { return !accept_key_.empty(); }
virtual EventHandler *next() {
if (finish()) {
int fd = fd_;
fd_ = -1;
return new HttpHandshakeSendHandler(fd, accept_key_);
@ -443,6 +380,7 @@ public:
return 0;
}
}
private:
int fd_;
std::string headers_;
@ -451,54 +389,35 @@ private:
class ListenEventHandler : public EventHandler {
public:
ListenEventHandler(int fd)
: fd_(fd), cfd_(-1)
{}
virtual ~ListenEventHandler()
{
ListenEventHandler(int fd) : fd_(fd), cfd_(-1) {}
virtual ~ListenEventHandler() {
close(fd_);
close(cfd_);
}
virtual int on_read_event()
{
if(cfd_ != -1) {
virtual int on_read_event() {
if (cfd_ != -1) {
close(cfd_);
}
while((cfd_ = accept(fd_, 0, 0)) == -1 && errno == EINTR);
if(cfd_ == -1) {
while ((cfd_ = accept(fd_, 0, 0)) == -1 && errno == EINTR)
;
if (cfd_ == -1) {
perror("accept");
}
return 0;
}
virtual int on_write_event()
{
return 0;
}
virtual bool want_read()
{
return true;
}
virtual bool want_write()
{
return false;
}
virtual int fd() const
{
return fd_;
}
virtual bool finish()
{
return false;
}
virtual EventHandler* next()
{
if(cfd_ != -1) {
virtual int on_write_event() { return 0; }
virtual bool want_read() { return true; }
virtual bool want_write() { return false; }
virtual int fd() const { return fd_; }
virtual bool finish() { return false; }
virtual EventHandler *next() {
if (cfd_ != -1) {
int val = 1;
int fd = cfd_;
cfd_ = -1;
if(make_non_block(fd) == -1 ||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
== -1) {
if (make_non_block(fd) == -1 ||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val,
(socklen_t)sizeof(val)) == -1) {
close(fd);
return 0;
}
@ -507,20 +426,20 @@ public:
return 0;
}
}
private:
int fd_;
int cfd_;
};
int ctl_epollev(int epollfd, int op, EventHandler *handler)
{
int ctl_epollev(int epollfd, int op, EventHandler *handler) {
epoll_event ev;
memset(&ev, 0, sizeof(ev));
int events = 0;
if(handler->want_read()) {
if (handler->want_read()) {
events |= EPOLLIN;
}
if(handler->want_write()) {
if (handler->want_write()) {
events |= EPOLLOUT;
}
ev.events = events;
@ -528,42 +447,41 @@ int ctl_epollev(int epollfd, int op, EventHandler *handler)
return epoll_ctl(epollfd, op, handler->fd(), &ev);
}
void reactor(int sfd)
{
std::set<EventHandler*> handlers;
ListenEventHandler* listen_handler = new ListenEventHandler(sfd);
void reactor(int sfd) {
std::set<EventHandler *> handlers;
ListenEventHandler *listen_handler = new ListenEventHandler(sfd);
handlers.insert(listen_handler);
int epollfd = epoll_create(16);
if(epollfd == -1) {
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
if(ctl_epollev(epollfd, EPOLL_CTL_ADD, listen_handler) == -1) {
if (ctl_epollev(epollfd, EPOLL_CTL_ADD, listen_handler) == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
static const size_t MAX_EVENTS = 64;
epoll_event events[MAX_EVENTS];
while(1) {
while (1) {
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if(nfds == -1) {
if (nfds == -1) {
perror("epoll_wait");
return;
}
for(int n = 0; n < nfds; ++n) {
EventHandler* eh = (EventHandler*)events[n].data.ptr;
if(((events[n].events & EPOLLIN) && eh->on_read_event() == -1) ||
((events[n].events & EPOLLOUT) && eh->on_write_event() == -1) ||
(events[n].events & (EPOLLERR | EPOLLHUP))) {
for (int n = 0; n < nfds; ++n) {
EventHandler *eh = (EventHandler *)events[n].data.ptr;
if (((events[n].events & EPOLLIN) && eh->on_read_event() == -1) ||
((events[n].events & EPOLLOUT) && eh->on_write_event() == -1) ||
(events[n].events & (EPOLLERR | EPOLLHUP))) {
handlers.erase(eh);
delete eh;
} else {
EventHandler* next = eh->next();
if(next) {
EventHandler *next = eh->next();
if (next) {
handlers.insert(next);
if(ctl_epollev(epollfd, EPOLL_CTL_ADD, next) == -1) {
if(errno == EEXIST) {
if(ctl_epollev(epollfd, EPOLL_CTL_MOD, next) == -1) {
if (ctl_epollev(epollfd, EPOLL_CTL_ADD, next) == -1) {
if (errno == EEXIST) {
if (ctl_epollev(epollfd, EPOLL_CTL_MOD, next) == -1) {
perror("epoll_ctl");
delete next;
}
@ -573,11 +491,11 @@ void reactor(int sfd)
}
}
}
if(eh->finish()) {
if (eh->finish()) {
handlers.erase(eh);
delete eh;
} else {
if(ctl_epollev(epollfd, EPOLL_CTL_MOD, eh) == -1) {
if (ctl_epollev(epollfd, EPOLL_CTL_MOD, eh) == -1) {
perror("epoll_ctl");
}
}
@ -586,9 +504,8 @@ void reactor(int sfd)
}
}
int main(int argc, char **argv)
{
if(argc < 2) {
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " PORT" << std::endl;
exit(EXIT_FAILURE);
}
@ -597,7 +514,7 @@ int main(int argc, char **argv)
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
int sfd = create_listen_socket(argv[1]);
if(sfd == -1) {
if (sfd == -1) {
std::cerr << "Failed to create server socket" << std::endl;
exit(EXIT_FAILURE);
}

View File

@ -60,8 +60,7 @@
* Create server socket, listen on *service*. This function returns
* file descriptor of server socket if it succeeds, or returns -1.
*/
int create_listen_socket(const char *service)
{
static int create_listen_socket(const char *service) {
struct addrinfo hints, *res, *rp;
int sfd = -1;
int r;
@ -70,27 +69,27 @@ int create_listen_socket(const char *service)
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
r = getaddrinfo(0, service, &hints, &res);
if(r != 0) {
if (r != 0) {
fprintf(stderr, "getaddrinfo: %s", gai_strerror(r));
return -1;
}
for(rp = res; rp; rp = rp->ai_next) {
for (rp = res; rp; rp = rp->ai_next) {
int val = 1;
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sfd == -1) {
if (sfd == -1) {
continue;
}
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
(socklen_t)sizeof(val)) == -1) {
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val,
(socklen_t)sizeof(val)) == -1) {
continue;
}
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
break;
}
close(sfd);
}
freeaddrinfo(res);
if(listen(sfd, 16) == -1) {
if (listen(sfd, 16) == -1) {
perror("listen");
close(sfd);
return -1;
@ -102,16 +101,17 @@ int create_listen_socket(const char *service)
* Makes file descriptor *fd* non-blocking mode.
* This function returns 0, or returns -1.
*/
int make_non_block(int fd)
{
static int make_non_block(int fd) {
int flags, r;
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
if(flags == -1) {
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
;
if (flags == -1) {
perror("fcntl");
return -1;
}
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
;
if (r == -1) {
perror("fcntl");
return -1;
}
@ -122,8 +122,7 @@ int make_non_block(int fd)
* Calculates SHA-1 hash of *src*. The size of *src* is *src_length* bytes.
* *dst* must be at least SHA1_DIGEST_SIZE.
*/
void sha1(uint8_t *dst, const uint8_t *src, size_t src_length)
{
static void sha1(uint8_t *dst, const uint8_t *src, size_t src_length) {
struct sha1_ctx ctx;
sha1_init(&ctx);
sha1_update(&ctx, src_length, src);
@ -135,11 +134,10 @@ void sha1(uint8_t *dst, const uint8_t *src, size_t src_length)
* The size of *src* is *src_length*.
* *dst* must be at least BASE64_ENCODE_RAW_LENGTH(src_length).
*/
void base64(uint8_t *dst, const uint8_t *src, size_t src_length)
{
static void base64(uint8_t *dst, const uint8_t *src, size_t src_length) {
struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
base64_encode_raw(dst, src_length, src);
base64_encode_raw((char *)dst, src_length, src);
}
#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
@ -150,13 +148,12 @@ void base64(uint8_t *dst, const uint8_t *src, size_t src_length)
* client's handshake and it must be length of 24.
* *dst* must be at least BASE64_ENCODE_RAW_LENGTH(20)+1.
*/
void create_accept_key(char *dst, const char *client_key)
{
static void create_accept_key(char *dst, const char *client_key) {
uint8_t sha1buf[20], key_src[60];
memcpy(key_src, client_key, 24);
memcpy(key_src+24, WS_GUID, 36);
memcpy(key_src + 24, WS_GUID, 36);
sha1(sha1buf, key_src, sizeof(key_src));
base64((uint8_t*)dst, sha1buf, 20);
base64((uint8_t *)dst, sha1buf, 20);
dst[BASE64_ENCODE_RAW_LENGTH(20)] = '\0';
}
@ -166,69 +163,59 @@ void create_accept_key(char *dst, const char *client_key)
* If the caller is looking for a specific value, we return a pointer to the
* start of that value, else we simply return the start of values list.
*/
static char*
http_header_find_field_value(char *header, char *field_name, char *value)
{
char *header_end,
*field_start,
*field_end,
*next_crlf,
*value_start;
static const char *http_header_find_field_value(const char *header,
const char *field_name,
const char *value) {
const char *header_end, *field_start, *field_end, *next_crlf, *value_start;
int field_name_len;
/* Pointer to the last character in the header */
header_end = header + strlen(header) - 1;
field_name_len = strlen(field_name);
field_name_len = (int)strlen(field_name);
field_start = header;
do{
field_start = strstr(field_start+1, field_name);
do {
field_start = strstr(field_start + 1, field_name);
field_end = field_start + field_name_len - 1;
if(field_start != NULL
&& field_start - header >= 2
&& field_start[-2] == '\r'
&& field_start[-1] == '\n'
&& header_end - field_end >= 1
&& field_end[1] == ':')
{
if (field_start != NULL && field_start - header >= 2 &&
field_start[-2] == '\r' && field_start[-1] == '\n' &&
header_end - field_end >= 1 && field_end[1] == ':') {
break; /* Found the field */
}
else
{
} else {
continue; /* This is not the one; keep looking. */
}
} while(field_start != NULL);
} while (field_start != NULL);
if(field_start == NULL)
if (field_start == NULL)
return NULL;
/* Find the field terminator */
next_crlf = strstr(field_start, "\r\n");
/* A field is expected to end with \r\n */
if(next_crlf == NULL)
if (next_crlf == NULL)
return NULL; /* Malformed HTTP header! */
/* If not looking for a value, then return a pointer to the start of values string */
if(value == NULL)
return field_end+2;
if (value == NULL)
return field_end + 2;
value_start = strstr(field_start, value);
/* Value not found */
if(value_start == NULL)
if (value_start == NULL)
return NULL;
/* Found the value we're looking for */
if(value_start > next_crlf)
if (value_start > next_crlf)
return NULL; /* ... but after the CRLF terminator of the field. */
/* The value we found should be properly delineated from the other tokens */
if(isalnum(value_start[-1]) || isalnum(value_start[strlen(value)]))
if (isalnum(value_start[-1]) || isalnum(value_start[strlen(value)]))
return NULL;
return value_start;
@ -239,48 +226,53 @@ http_header_find_field_value(char *header, char *field_name, char *value)
* connection to the client. This function returns 0 if it succeeds,
* or returns -1.
*/
int http_handshake(int fd)
{
static int http_handshake(int fd) {
/*
* Note: The implementation of HTTP handshake in this function is
* written for just a example of how to use of wslay library and is
* not meant to be used in production code. In practice, you need
* to do more strict verification of the client's handshake.
*/
char header[16384], accept_key[29], *keyhdstart, *keyhdend, res_header[256];
char header[16384], accept_key[29], res_header[256];
const char *keyhdstart, *keyhdend;
size_t header_length = 0, res_header_sent = 0, res_header_length;
ssize_t r;
while(1) {
while((r = read(fd, header+header_length,
sizeof(header)-header_length)) == -1 && errno == EINTR);
if(r == -1) {
while (1) {
while ((r = read(fd, header + header_length,
sizeof(header) - header_length)) == -1 &&
errno == EINTR)
;
if (r == -1) {
perror("read");
return -1;
} else if(r == 0) {
} else if (r == 0) {
fprintf(stderr, "HTTP Handshake: Got EOF");
return -1;
} else {
header_length += r;
if(header_length >= 4 &&
memcmp(header+header_length-4, "\r\n\r\n", 4) == 0) {
header_length += (size_t)r;
if (header_length >= 4 &&
memcmp(header + header_length - 4, "\r\n\r\n", 4) == 0) {
break;
} else if(header_length == sizeof(header)) {
} else if (header_length == sizeof(header)) {
fprintf(stderr, "HTTP Handshake: Too large HTTP headers");
return -1;
}
}
}
if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
(keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key", NULL)) == NULL) {
if (http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
(keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key",
NULL)) == NULL) {
fprintf(stderr, "HTTP Handshake: Missing required header fields");
return -1;
}
for(; *keyhdstart == ' '; ++keyhdstart);
for (; *keyhdstart == ' '; ++keyhdstart)
;
keyhdend = keyhdstart;
for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);
if(keyhdend-keyhdstart != 24) {
for (; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend)
;
if (keyhdend - keyhdstart != 24) {
printf("%s\n", keyhdstart);
fprintf(stderr, "HTTP Handshake: Invalid value in Sec-WebSocket-Key");
return -1;
@ -291,17 +283,19 @@ int http_handshake(int fd)
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"\r\n", accept_key);
"\r\n",
accept_key);
res_header_length = strlen(res_header);
while(res_header_sent < res_header_length) {
while((r = write(fd, res_header+res_header_sent,
res_header_length-res_header_sent)) == -1 &&
errno == EINTR);
if(r == -1) {
while (res_header_sent < res_header_length) {
while ((r = write(fd, res_header + res_header_sent,
res_header_length - res_header_sent)) == -1 &&
errno == EINTR)
;
if (r == -1) {
perror("write");
return -1;
} else {
res_header_sent += r;
res_header_sent += (size_t)r;
}
}
return 0;
@ -315,21 +309,20 @@ struct Session {
int fd;
};
ssize_t send_callback(wslay_event_context_ptr ctx,
const uint8_t *data, size_t len, int flags,
void *user_data)
{
struct Session *session = (struct Session*)user_data;
static ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
size_t len, int flags, void *user_data) {
struct Session *session = (struct Session *)user_data;
ssize_t r;
int sflags = 0;
#ifdef MSG_MORE
if(flags & WSLAY_MSG_MORE) {
if (flags & WSLAY_MSG_MORE) {
sflags |= MSG_MORE;
}
#endif // MSG_MORE
while((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
while ((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR)
;
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
@ -338,19 +331,20 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
return r;
}
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
int flags, void *user_data)
{
struct Session *session = (struct Session*)user_data;
static ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf,
size_t len, int flags, void *user_data) {
struct Session *session = (struct Session *)user_data;
ssize_t r;
while((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
(void)flags;
while ((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR)
;
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
}
} else if(r == 0) {
} else if (r == 0) {
/* Unexpected EOF is also treated as an error */
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
r = -1;
@ -358,15 +352,13 @@ ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
return r;
}
void on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
static void on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data) {
(void)user_data;
/* Echo back non-control message */
if(!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {
arg->opcode, arg->msg, arg->msg_length
};
if (!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
wslay_event_queue_msg(ctx, &msgarg);
}
}
@ -377,31 +369,24 @@ void on_msg_recv_callback(wslay_event_context_ptr ctx,
* error occurs. *fd* is the file descriptor of the connection to the
* client. This function returns 0 if it succeeds, or returns 0.
*/
int communicate(int fd)
{
static int communicate(int fd) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks = {
recv_callback,
send_callback,
NULL,
NULL,
NULL,
NULL,
on_msg_recv_callback
};
struct Session session = { fd };
recv_callback, send_callback, NULL, NULL, NULL,
NULL, on_msg_recv_callback};
struct Session session = {fd};
int val = 1;
struct pollfd event;
int res = 0;
if(http_handshake(fd) == -1) {
if (http_handshake(fd) == -1) {
return -1;
}
if(make_non_block(fd) == -1) {
if (make_non_block(fd) == -1) {
return -1;
}
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
== -1) {
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) ==
-1) {
perror("setsockopt: TCP_NODELAY");
return -1;
}
@ -413,17 +398,18 @@ int communicate(int fd)
* Event loop: basically loop until both wslay_event_want_read(ctx)
* and wslay_event_want_write(ctx) return 0.
*/
while(wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) {
while (wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) {
int r;
while((r = poll(&event, 1, -1)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = poll(&event, 1, -1)) == -1 && errno == EINTR)
;
if (r == -1) {
perror("poll");
res = -1;
break;
}
if(((event.revents & POLLIN) && wslay_event_recv(ctx) != 0) ||
((event.revents & POLLOUT) && wslay_event_send(ctx) != 0) ||
(event.revents & (POLLERR | POLLHUP | POLLNVAL))) {
if (((event.revents & POLLIN) && wslay_event_recv(ctx) != 0) ||
((event.revents & POLLOUT) && wslay_event_send(ctx) != 0) ||
(event.revents & (POLLERR | POLLHUP | POLLNVAL))) {
/*
* If either wslay_event_recv() or wslay_event_send() return
* non-zero value, it means serious error which prevents wslay
@ -434,10 +420,10 @@ int communicate(int fd)
break;
}
event.events = 0;
if(wslay_event_want_read(ctx)) {
if (wslay_event_want_read(ctx)) {
event.events |= POLLIN;
}
if(wslay_event_want_write(ctx)) {
if (wslay_event_want_write(ctx)) {
event.events |= POLLOUT;
}
}
@ -451,23 +437,23 @@ int communicate(int fd)
* process communicates with client. The parent process goes back to
* the loop and can accept another client.
*/
void serve(int sfd)
{
while(1) {
static void __attribute__((noreturn)) serve(int sfd) {
while (1) {
int fd;
while((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR);
if(fd == -1) {
while ((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR)
;
if (fd == -1) {
perror("accept");
} else {
int r = fork();
if(r == -1) {
if (r == -1) {
perror("fork");
close(fd);
} else if(r == 0) {
int r = communicate(fd);
} else if (r == 0) {
r = communicate(fd);
shutdown(fd, SHUT_WR);
close(fd);
if(r == 0) {
if (r == 0) {
exit(EXIT_SUCCESS);
} else {
exit(EXIT_FAILURE);
@ -477,11 +463,10 @@ void serve(int sfd)
}
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
struct sigaction act;
int sfd;
if(argc < 2) {
if (argc < 2) {
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
exit(EXIT_FAILURE);
}
@ -491,7 +476,7 @@ int main(int argc, char **argv)
sigaction(SIGCHLD, &act, NULL);
sfd = create_listen_socket(argv[1]);
if(sfd == -1) {
if (sfd == -1) {
fprintf(stderr, "Failed to create server socket\n");
exit(EXIT_FAILURE);
}

View File

@ -52,8 +52,7 @@
#include <nettle/sha.h>
#include <wslay/wslay.h>
int connect_to(const char *host, const char *service)
{
int connect_to(const char *host, const char *service) {
struct addrinfo hints;
int fd = -1;
int r;
@ -62,18 +61,19 @@ int connect_to(const char *host, const char *service)
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *res;
r = getaddrinfo(host, service, &hints, &res);
if(r != 0) {
if (r != 0) {
std::cerr << "getaddrinfo: " << gai_strerror(r) << std::endl;
return -1;
}
for(struct addrinfo *rp = res; rp; rp = rp->ai_next) {
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(fd == -1) {
if (fd == -1) {
continue;
}
while((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR);
if(r == 0) {
while ((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
errno == EINTR)
;
if (r == 0) {
break;
}
close(fd);
@ -83,91 +83,77 @@ int connect_to(const char *host, const char *service)
return fd;
}
int make_non_block(int fd)
{
int make_non_block(int fd) {
int flags, r;
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
if(flags == -1) {
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
;
if (flags == -1) {
return -1;
}
while((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
if(r == -1) {
while ((r = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
;
if (r == -1) {
return -1;
}
return 0;
}
std::string sha1(const std::string& src)
{
std::string sha1(const std::string &src) {
sha1_ctx ctx;
sha1_init(&ctx);
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t*>(src.c_str()));
sha1_update(&ctx, src.size(), reinterpret_cast<const uint8_t *>(src.c_str()));
uint8_t temp[SHA1_DIGEST_SIZE];
sha1_digest(&ctx, SHA1_DIGEST_SIZE, temp);
std::string res(&temp[0], &temp[SHA1_DIGEST_SIZE]);
return res;
}
std::string base64(const std::string& src)
{
std::string base64(const std::string &src) {
base64_encode_ctx ctx;
base64_encode_init(&ctx);
int dstlen = BASE64_ENCODE_RAW_LENGTH(src.size());
uint8_t *dst = new uint8_t[dstlen];
char *dst = new char[dstlen];
base64_encode_raw(dst, src.size(),
reinterpret_cast<const uint8_t*>(src.c_str()));
reinterpret_cast<const uint8_t *>(src.c_str()));
std::string res(&dst[0], &dst[dstlen]);
delete [] dst;
delete[] dst;
return res;
}
std::string create_acceptkey(const std::string& clientkey)
{
std::string s = clientkey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string create_acceptkey(const std::string &clientkey) {
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
return base64(sha1(s));
}
class WebSocketClient {
public:
WebSocketClient(int fd, struct wslay_event_callbacks *callbacks,
const std::string& body)
: fd_(fd),
body_(body),
body_off_(0),
dev_urand_("/dev/urandom")
{
const std::string &body)
: fd_(fd), body_(body), body_off_(0), dev_urand_("/dev/urandom") {
wslay_event_context_client_init(&ctx_, callbacks, this);
}
~WebSocketClient()
{
~WebSocketClient() {
wslay_event_context_free(ctx_);
shutdown(fd_, SHUT_WR);
close(fd_);
}
int on_read_event()
{
return wslay_event_recv(ctx_);
}
int on_write_event()
{
return wslay_event_send(ctx_);
}
ssize_t send_data(const uint8_t *data, size_t len, int flags)
{
int on_read_event() { return wslay_event_recv(ctx_); }
int on_write_event() { return wslay_event_send(ctx_); }
ssize_t send_data(const uint8_t *data, size_t len, int flags) {
ssize_t r;
int sflags = 0;
#ifdef MSG_MORE
if(flags & WSLAY_MSG_MORE) {
if (flags & WSLAY_MSG_MORE) {
sflags |= MSG_MORE;
}
#endif // MSG_MORE
while((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR);
while ((r = send(fd_, data, len, sflags)) == -1 && errno == EINTR)
;
return r;
}
ssize_t feed_body(uint8_t *data, size_t len)
{
if(body_off_ < body_.size()) {
size_t wlen = std::min(len, body_.size()-body_off_);
ssize_t feed_body(uint8_t *data, size_t len) {
if (body_off_ < body_.size()) {
size_t wlen = std::min(len, body_.size() - body_off_);
memcpy(data, body_.c_str(), wlen);
body_off_ += wlen;
return wlen;
@ -175,32 +161,22 @@ public:
return 0;
}
}
ssize_t recv_data(uint8_t *data, size_t len, int flags)
{
ssize_t recv_data(uint8_t *data, size_t len, int flags) {
ssize_t r;
while((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR);
while ((r = recv(fd_, data, len, 0)) == -1 && errno == EINTR)
;
return r;
}
bool want_read()
{
return wslay_event_want_read(ctx_);
bool want_read() { return wslay_event_want_read(ctx_); }
bool want_write() { return wslay_event_want_write(ctx_); }
int fd() const { return fd_; }
void get_random(uint8_t *buf, size_t len) {
dev_urand_.read((char *)buf, len);
}
bool want_write()
{
return wslay_event_want_write(ctx_);
}
int fd() const
{
return fd_;
}
void get_random(uint8_t *buf, size_t len)
{
dev_urand_.read((char*)buf, len);
}
void set_callbacks(const struct wslay_event_callbacks *callbacks)
{
void set_callbacks(const struct wslay_event_callbacks *callbacks) {
wslay_event_config_set_callbacks(ctx_, callbacks);
}
private:
int fd_;
wslay_event_context_ptr ctx_;
@ -209,14 +185,12 @@ private:
std::fstream dev_urand_;
};
ssize_t send_callback(wslay_event_context_ptr ctx,
const uint8_t *data, size_t len, int flags,
void *user_data)
{
WebSocketClient *ws = (WebSocketClient*)user_data;
ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data,
size_t len, int flags, void *user_data) {
WebSocketClient *ws = (WebSocketClient *)user_data;
ssize_t r = ws->send_data(data, len, flags);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
@ -226,71 +200,63 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
}
ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
int flags, void *user_data)
{
WebSocketClient *ws = (WebSocketClient*)user_data;
int flags, void *user_data) {
WebSocketClient *ws = (WebSocketClient *)user_data;
ssize_t r = ws->recv_data(data, len, flags);
if(r == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
if (r == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
} else {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
}
} else if(r == 0) {
} else if (r == 0) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
r = -1;
}
return r;
}
ssize_t feed_body_callback
(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags,
void *user_data)
{
WebSocketClient *ws = (WebSocketClient*)user_data;
ssize_t feed_body_callback(wslay_event_context_ptr ctx, uint8_t *data,
size_t len, int flags, void *user_data) {
WebSocketClient *ws = (WebSocketClient *)user_data;
return ws->feed_body(data, len);
}
int genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
void *user_data)
{
WebSocketClient *ws = (WebSocketClient*)user_data;
void *user_data) {
WebSocketClient *ws = (WebSocketClient *)user_data;
ws->get_random(buf, len);
return 0;
}
void on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
if(!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {
arg->opcode, arg->msg, arg->msg_length
};
void *user_data) {
if (!wslay_is_ctrl_frame(arg->opcode)) {
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
wslay_event_queue_msg(ctx, &msgarg);
}
}
std::string casecntjson;
void get_casecnt_on_msg_recv_callback
(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
if(arg->opcode == WSLAY_TEXT_FRAME) {
casecntjson.assign(arg->msg, arg->msg+arg->msg_length);
void get_casecnt_on_msg_recv_callback(
wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg,
void *user_data) {
if (arg->opcode == WSLAY_TEXT_FRAME) {
casecntjson.assign(arg->msg, arg->msg + arg->msg_length);
}
}
int send_http_handshake(int fd, const std::string& reqheader)
{
int send_http_handshake(int fd, const std::string &reqheader) {
size_t off = 0;
while(off < reqheader.size()) {
while (off < reqheader.size()) {
ssize_t r;
size_t len = reqheader.size()-off;
while((r = write(fd, reqheader.c_str()+off, len)) == -1 && errno == EINTR);
if(r == -1) {
size_t len = reqheader.size() - off;
while ((r = write(fd, reqheader.c_str() + off, len)) == -1 &&
errno == EINTR)
;
if (r == -1) {
perror("write");
return -1;
}
@ -299,20 +265,20 @@ int send_http_handshake(int fd, const std::string& reqheader)
return 0;
}
int recv_http_handshake(int fd, std::string& resheader)
{
int recv_http_handshake(int fd, std::string &resheader) {
char buf[4096];
while(1) {
while (1) {
ssize_t r;
while((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR);
if(r <= 0) {
while ((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR)
;
if (r <= 0) {
return -1;
}
resheader.append(buf, buf+r);
if(resheader.find("\r\n\r\n") != std::string::npos) {
resheader.append(buf, buf + r);
if (resheader.find("\r\n\r\n") != std::string::npos) {
break;
}
if(resheader.size() > 8192) {
if (resheader.size() > 8192) {
std::cerr << "Too big response header" << std::endl;
return -1;
}
@ -320,17 +286,15 @@ int recv_http_handshake(int fd, std::string& resheader)
return 0;
}
std::string get_random16()
{
std::string get_random16() {
char buf[16];
std::fstream f("/dev/urandom");
f.read(buf, 16);
return std::string(buf, buf+16);
return std::string(buf, buf + 16);
}
int http_handshake(int fd, const char *host, const char *service,
const char *path, std::string& body)
{
const char *path, std::string &body) {
char buf[4096];
std::string client_key = base64(get_random16());
snprintf(buf, sizeof(buf),
@ -343,77 +307,75 @@ int http_handshake(int fd, const char *host, const char *service,
"\r\n",
path, host, service, client_key.c_str());
std::string reqheader = buf;
if(send_http_handshake(fd, reqheader) == -1) {
if (send_http_handshake(fd, reqheader) == -1) {
return -1;
}
std::string resheader;
if(recv_http_handshake(fd, resheader) == -1) {
if (recv_http_handshake(fd, resheader) == -1) {
return -1;
}
std::string::size_type keyhdstart;
if((keyhdstart = resheader.find("Sec-WebSocket-Accept: ")) ==
std::string::npos) {
if ((keyhdstart = resheader.find("Sec-WebSocket-Accept: ")) ==
std::string::npos) {
std::cerr << "http_upgrade: missing required headers" << std::endl;
return -1;
}
keyhdstart += 22;
std::string::size_type keyhdend = resheader.find("\r\n", keyhdstart);
std::string accept_key = resheader.substr(keyhdstart, keyhdend-keyhdstart);
if(accept_key == create_acceptkey(client_key)) {
body = resheader.substr(resheader.find("\r\n\r\n")+4);
std::string accept_key = resheader.substr(keyhdstart, keyhdend - keyhdstart);
if (accept_key == create_acceptkey(client_key)) {
body = resheader.substr(resheader.find("\r\n\r\n") + 4);
return 0;
} else {
return -1;
}
}
void ctl_epollev(int epollfd, int op, WebSocketClient& ws)
{
void ctl_epollev(int epollfd, int op, WebSocketClient &ws) {
epoll_event ev;
memset(&ev, 0, sizeof(ev));
if(ws.want_read()) {
if (ws.want_read()) {
ev.events |= EPOLLIN;
}
if(ws.want_write()) {
if (ws.want_write()) {
ev.events |= EPOLLOUT;
}
if(epoll_ctl(epollfd, op, ws.fd(), &ev) == -1) {
if (epoll_ctl(epollfd, op, ws.fd(), &ev) == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
}
int communicate(const char *host, const char *service, const char *path,
const struct wslay_event_callbacks *callbacks)
{
const struct wslay_event_callbacks *callbacks) {
struct wslay_event_callbacks cb = *callbacks;
cb.recv_callback = feed_body_callback;
int fd = connect_to(host, service);
if(fd == -1) {
if (fd == -1) {
std::cerr << "Could not connect to the host" << std::endl;
return -1;
}
std::string body;
if(http_handshake(fd, host, service, path, body) == -1) {
if (http_handshake(fd, host, service, path, body) == -1) {
std::cerr << "Failed handshake" << std::endl;
close(fd);
return -1;
}
make_non_block(fd);
int val = 1;
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val))
== -1) {
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) ==
-1) {
perror("setsockopt: TCP_NODELAY");
return -1;
}
WebSocketClient ws(fd, &cb, body);
if(ws.on_read_event() == -1) {
if (ws.on_read_event() == -1) {
return -1;
}
cb.recv_callback = callbacks->recv_callback;
ws.set_callbacks(&cb);
int epollfd = epoll_create(1);
if(epollfd == -1) {
if (epollfd == -1) {
perror("epoll_create");
return -1;
}
@ -421,20 +383,20 @@ int communicate(const char *host, const char *service, const char *path,
static const size_t MAX_EVENTS = 1;
epoll_event events[MAX_EVENTS];
bool ok = true;
while(ws.want_read() || ws.want_write()) {
while (ws.want_read() || ws.want_write()) {
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if(nfds == -1) {
if (nfds == -1) {
perror("epoll_wait");
return -1;
}
for(int n = 0; n < nfds; ++n) {
if(((events[n].events & EPOLLIN) && ws.on_read_event() != 0) ||
((events[n].events & EPOLLOUT) && ws.on_write_event() != 0)) {
for (int n = 0; n < nfds; ++n) {
if (((events[n].events & EPOLLIN) && ws.on_read_event() != 0) ||
((events[n].events & EPOLLOUT) && ws.on_write_event() != 0)) {
ok = false;
break;
}
}
if(!ok) {
if (!ok) {
break;
}
ctl_epollev(epollfd, EPOLL_CTL_MOD, ws);
@ -442,61 +404,53 @@ int communicate(const char *host, const char *service, const char *path,
return ok ? 0 : -1;
}
int get_casecnt(const char *host, const char *service)
{
int get_casecnt(const char *host, const char *service) {
struct wslay_event_callbacks callbacks = {
recv_callback,
send_callback,
genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
get_casecnt_on_msg_recv_callback
};
if(communicate(host, service, "/getCaseCount", &callbacks) == -1) {
recv_callback,
send_callback,
genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
get_casecnt_on_msg_recv_callback};
if (communicate(host, service, "/getCaseCount", &callbacks) == -1) {
return -1;
}
errno = 0;
int casecnt = strtol(casecntjson.c_str(), 0, 10);
if(errno == ERANGE) {
if (errno == ERANGE) {
return -1;
} else {
return casecnt;
}
}
int run_testcase(const char *host, const char *service, int casenum)
{
int run_testcase(const char *host, const char *service, int casenum) {
struct wslay_event_callbacks callbacks = {
recv_callback,
send_callback,
genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
on_msg_recv_callback
};
recv_callback,
send_callback,
genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
on_msg_recv_callback};
char buf[1024];
snprintf(buf, sizeof(buf), "/runCase?case=%d&agent=wslay", casenum);
return communicate(host, service, buf, &callbacks);
}
int update_reports(const char *host, const char *service)
{
int update_reports(const char *host, const char *service) {
struct wslay_event_callbacks callbacks = {
recv_callback,
send_callback,
genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
NULL, /* on_msg_recv_callback */
recv_callback, send_callback, genmask_callback,
NULL, /* on_frame_recv_start_callback */
NULL, /* on_frame_recv_callback */
NULL, /* on_frame_recv_end_callback */
NULL, /* on_msg_recv_callback */
};
return communicate(host, service, "/updateReports?&agent=wslay", &callbacks);
}
int main(int argc, char **argv)
{
if(argc < 3) {
int main(int argc, char **argv) {
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " HOST SERV" << std::endl;
exit(EXIT_FAILURE);
}
@ -507,17 +461,17 @@ int main(int argc, char **argv)
const char *host = argv[1];
const char *service = argv[2];
int casecnt = get_casecnt(host, service);
if(casecnt == -1) {
if (casecnt == -1) {
std::cerr << "Failed to get case count." << std::endl;
exit(EXIT_FAILURE);
}
for(int i = 1; i <= casecnt; ++i) {
for (int i = 1; i <= casecnt; ++i) {
std::cout << "Running test case " << i << std::endl;
if(run_testcase(host, service, i) == -1) {
if (run_testcase(host, service, i) == -1) {
std::cout << "Detected error during test" << std::endl;
}
}
if(update_reports(host, service) == -1) {
if (update_reports(host, service) == -1) {
std::cerr << "Failed to update reports." << std::endl;
exit(EXIT_FAILURE);
}

View File

@ -33,7 +33,7 @@ OBJECTS = wslay_frame.c wslay_event.c\
wslay_queue.c wslay_net.c
HFILES = wslay_frame.h wslay_event.h\
wslay_queue.h wslay_net.h
wslay_queue.h wslay_net.h wslay_macro.h
libwslay_la_SOURCES = $(HFILES) $(OBJECTS)
libwslay_la_LDFLAGS = -no-undefined \

View File

@ -25,7 +25,7 @@
#ifndef WSLAY_H
#define WSLAY_H
#ifdef __cplusplus
#ifdef __cplusplus
extern "C" {
#endif
@ -33,7 +33,6 @@ extern "C" {
#include <stdlib.h>
#include <sys/types.h>
/*
* wslay/wslayver.h is generated from wslay/wslayver.h.in by
* configure. The projects which do not use autotools can set
@ -149,10 +148,10 @@ enum wslay_opcode {
* These macros assume that rsv is constructed by ((RSV1 << 2) |
* (RSV2 << 1) | RSV3)
*/
#define WSLAY_RSV_NONE ((uint8_t) 0)
#define WSLAY_RSV1_BIT (((uint8_t) 1) << 2)
#define WSLAY_RSV2_BIT (((uint8_t) 1) << 1)
#define WSLAY_RSV3_BIT (((uint8_t) 1) << 0)
#define WSLAY_RSV_NONE ((uint8_t)0)
#define WSLAY_RSV1_BIT (((uint8_t)1) << 2)
#define WSLAY_RSV2_BIT (((uint8_t)1) << 1)
#define WSLAY_RSV3_BIT (((uint8_t)1) << 0)
#define wslay_get_rsv1(rsv) ((rsv >> 2) & 1)
#define wslay_get_rsv2(rsv) ((rsv >> 1) & 1)
@ -166,7 +165,7 @@ struct wslay_frame_iocb {
* RFC6455 requires 0 unless extensions are negotiated.
*/
uint8_t rsv;
/* 4 bit opcode */
/* 4 bit opcode */
uint8_t opcode;
/* payload length [0, 2**63-1] */
uint64_t payload_length;
@ -222,6 +221,33 @@ void wslay_frame_context_free(wslay_frame_context_ptr ctx);
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb);
/*
* Write WebSocket frame specified in iocb to buf of length
* buflen. ctx must be initialized using wslay_frame_context_init()
* function. iocb->fin must be 1 if this is a fin frame, otherwise 0.
* iocb->rsv is reserved bits. iocb->opcode must be the opcode of
* this frame. iocb->mask must be 1 if this is masked frame,
* otherwise 0. iocb->payload_length is the payload_length of this
* frame. iocb->data must point to the payload data to be
* sent. iocb->data_length must be the length of the data. Unlike
* wslay_frame_send, this function does not call send_callback
* function. This function calls gen_mask_callback function if it
* needs new mask key. This function returns the number of bytes
* written to a buffer. Unlike wslay_frame_send, it includes the
* number of header bytes. Instead, the number of payload bytes
* written is assigned to *pwpayloadlen if this function succeeds. If
* there is not enough space left in a buffer, it returns 0. If the
* library detects error in iocb, this function returns
* WSLAY_ERR_INVALID_ARGUMENT. If callback functions report a
* failure, this function returns WSLAY_ERR_INVALID_CALLBACK. This
* function does not always send all given data in iocb. If there are
* remaining data to be sent, adjust data and data_length in iocb
* accordingly and call this function again.
*/
ssize_t wslay_frame_write(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb, uint8_t *buf,
size_t buflen, size_t *pwpayloadlen);
/*
* Receives WebSocket frame and stores it in iocb. This function
* returns the number of payload bytes received. This does not
@ -270,9 +296,9 @@ struct wslay_event_on_msg_recv_arg {
* Callback function invoked by wslay_event_recv() when a message is
* completely received.
*/
typedef void (*wslay_event_on_msg_recv_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
typedef void (*wslay_event_on_msg_recv_callback)(
wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg,
void *user_data);
struct wslay_event_on_frame_recv_start_arg {
/* fin bit; 1 for final frame, or 0. */
@ -290,9 +316,9 @@ struct wslay_event_on_frame_recv_start_arg {
* starts to be received. This callback function is only invoked once
* for each frame.
*/
typedef void (*wslay_event_on_frame_recv_start_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
typedef void (*wslay_event_on_frame_recv_start_callback)(
wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
struct wslay_event_on_frame_recv_chunk_arg {
/* chunk of payload data */
@ -305,16 +331,16 @@ struct wslay_event_on_frame_recv_chunk_arg {
* Callback function invoked by wslay_event_recv() when a chunk of
* frame payload is received.
*/
typedef void (*wslay_event_on_frame_recv_chunk_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
typedef void (*wslay_event_on_frame_recv_chunk_callback)(
wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when a frame is
* completely received.
*/
typedef void (*wslay_event_on_frame_recv_end_callback)
(wslay_event_context_ptr ctx, void *user_data);
typedef void (*wslay_event_on_frame_recv_end_callback)(
wslay_event_context_ptr ctx, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when it wants to
@ -388,9 +414,9 @@ struct wslay_event_callbacks {
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_context_server_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks, void *user_data);
int wslay_event_context_server_init(
wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
void *user_data);
/*
* Initializes ctx as WebSocket client. user_data is an arbitrary
@ -403,9 +429,9 @@ int wslay_event_context_server_init
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_context_client_init
(wslay_event_context_ptr *ctx,
const struct wslay_event_callbacks *callbacks, void *user_data);
int wslay_event_context_client_init(
wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
void *user_data);
/*
* Releases allocated resources for ctx.
@ -456,8 +482,8 @@ void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
* or wslay_event_context_server_init() or
* wslay_event_context_client_init() are replaced with callbacks.
*/
void wslay_event_config_set_callbacks
(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
void wslay_event_config_set_callbacks(
wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
/*
* Receives messages from peer. When receiving
@ -532,6 +558,50 @@ int wslay_event_recv(wslay_event_context_ptr ctx);
*/
int wslay_event_send(wslay_event_context_ptr ctx);
/*
* Writes queued messages to a buffer. Unlike wslay_event_send(), this
* function writes messages into the given buffer. It does not use
* wslay_event_send_callback function. Single call of
* wslay_event_write() writes multiple messages until there is not
* enough space left in a buffer.
*
* If ctx is initialized for WebSocket client use, wslay_event_write()
* uses wslay_event_genmask_callback to get new mask key.
*
* buf is a pointer to buffer and its capacity is given in buflen. It
* should have at least 14 bytes.
*
* When a message queued using wslay_event_queue_fragmented_msg() is
* sent, wslay_event_write() invokes
* wslay_event_fragmented_msg_callback for that message.
*
* After close control frame is sent, this function calls
* wslay_event_set_write_enabled() with second argument 0 to disable
* further transmission to peer.
*
* If there are any pending messages, wslay_event_want_write() returns
* 1, otherwise returns 0.
*
* In case of a fatal errror which leads to negative return code, this
* function calls wslay_event_set_write_enabled() with second argument
* 0 to disable further transmission to peer.
*
* wslay_event_write() returns the number of bytes written to a buffer
* if it succeeds, or one of the following negative error codes:
*
* WSLAY_ERR_CALLBACK_FAILURE
* User defined callback function is failed.
*
* WSLAY_ERR_NOMEM
* Out of memory.
*
* When negative error code is returned, application must not make any
* further call of wslay_event_write() and must close WebSocket
* connection.
*/
ssize_t wslay_event_write(wslay_event_context_ptr ctx, uint8_t *buf,
size_t buflen);
struct wslay_event_msg {
uint8_t opcode;
const uint8_t *msg;
@ -588,10 +658,9 @@ union wslay_event_msg_source {
* moment, return 0. If there is an error, return -1 and set error
* code WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error().
*/
typedef ssize_t (*wslay_event_fragmented_msg_callback)
(wslay_event_context_ptr ctx,
uint8_t *buf, size_t len, const union wslay_event_msg_source *source,
int *eof, void *user_data);
typedef ssize_t (*wslay_event_fragmented_msg_callback)(
wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
const union wslay_event_msg_source *source, int *eof, void *user_data);
struct wslay_event_fragmented_msg {
/* opcode */
@ -625,15 +694,16 @@ struct wslay_event_fragmented_msg {
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_queue_fragmented_msg
(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
int wslay_event_queue_fragmented_msg(
wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
/*
* Extended version of wslay_event_queue_fragmented_msg which allows to set
* reserved bits.
*/
int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
const struct wslay_event_fragmented_msg *arg, uint8_t rsv);
int wslay_event_queue_fragmented_msg_ex(
wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg,
uint8_t rsv);
/*
* Queues close control frame. This function is provided just for
@ -663,8 +733,7 @@ int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
* WSLAY_ERR_NOMEM
* Out of memory.
*/
int wslay_event_queue_close(wslay_event_context_ptr ctx,
uint16_t status_code,
int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
const uint8_t *reason, size_t reason_length);
/*

File diff suppressed because it is too large Load Diff

View File

@ -31,10 +31,10 @@
#include <wslay/wslay.h>
struct wslay_stack;
struct wslay_queue;
#include "wslay_queue.h"
struct wslay_event_byte_chunk {
struct wslay_queue_entry qe;
uint8_t *data;
size_t data_length;
};
@ -44,16 +44,14 @@ struct wslay_event_imsg {
uint8_t rsv;
uint8_t opcode;
uint32_t utf8state;
struct wslay_queue *chunks;
struct wslay_queue chunks;
size_t msg_length;
};
enum wslay_event_msg_type {
WSLAY_NON_FRAGMENTED,
WSLAY_FRAGMENTED
};
enum wslay_event_msg_type { WSLAY_NON_FRAGMENTED, WSLAY_FRAGMENTED };
struct wslay_event_omsg {
struct wslay_queue_entry qe;
uint8_t fin;
uint8_t opcode;
uint8_t rsv;
@ -77,9 +75,7 @@ enum wslay_event_close_status {
WSLAY_CLOSE_SENT = 1 << 2
};
enum wslay_event_config {
WSLAY_CONFIG_NO_BUFFERING = 1 << 0
};
enum wslay_event_config { WSLAY_CONFIG_NO_BUFFERING = 1 << 0 };
struct wslay_event_context {
/* config status, bitwise OR of enum wslay_event_config values*/
@ -118,9 +114,9 @@ struct wslay_event_context {
is currently sent. */
struct wslay_event_omsg *omsg;
/* Queue for non-control frames */
struct wslay_queue/*<wslay_omsg*>*/ *send_queue;
struct wslay_queue /*<wslay_omsg*>*/ send_queue;
/* Queue for control frames */
struct wslay_queue/*<wslay_omsg*>*/ *send_ctrl_queue;
struct wslay_queue /*<wslay_omsg*>*/ send_ctrl_queue;
/* Size of send_queue + size of send_ctrl_queue */
size_t queued_msg_count;
/* The sum of message length in send_queue */

View File

@ -34,10 +34,9 @@
int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
const struct wslay_frame_callbacks *callbacks,
void *user_data)
{
*ctx = (wslay_frame_context_ptr)malloc(sizeof(struct wslay_frame_context));
if(*ctx == NULL) {
void *user_data) {
*ctx = malloc(sizeof(struct wslay_frame_context));
if (*ctx == NULL) {
return -1;
}
memset(*ctx, 0, sizeof(struct wslay_frame_context));
@ -50,38 +49,35 @@ int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
return 0;
}
void wslay_frame_context_free(wslay_frame_context_ptr ctx)
{
free(ctx);
}
void wslay_frame_context_free(wslay_frame_context_ptr ctx) { free(ctx); }
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb)
{
if(iocb->data_length > iocb->payload_length) {
struct wslay_frame_iocb *iocb) {
if (iocb->data_length > iocb->payload_length) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(ctx->ostate == PREP_HEADER) {
if (ctx->ostate == PREP_HEADER) {
uint8_t *hdptr = ctx->oheader;
memset(ctx->oheader, 0, sizeof(ctx->oheader));
*hdptr |= (iocb->fin << 7) & 0x80u;
*hdptr |= (iocb->rsv << 4) & 0x70u;
*hdptr |= iocb->opcode & 0xfu;
*hdptr |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
*hdptr |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
/* Suppress stubborn gcc-10 warning */
*hdptr |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
++hdptr;
*hdptr |= (iocb->mask << 7) & 0x80u;
if(wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
*hdptr |= (uint8_t)((uint8_t)(iocb->mask << 7) & 0x80u);
if (wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(iocb->payload_length < 126) {
*hdptr |= iocb->payload_length;
if (iocb->payload_length < 126) {
*hdptr |= (uint8_t)iocb->payload_length;
++hdptr;
} else if(iocb->payload_length < (1 << 16)) {
uint16_t len = htons(iocb->payload_length);
} else if (iocb->payload_length < (1 << 16)) {
uint16_t len = htons((uint16_t)iocb->payload_length);
*hdptr |= 126;
++hdptr;
memcpy(hdptr, &len, 2);
hdptr += 2;
} else if(iocb->payload_length < (1ull << 63)) {
} else if (iocb->payload_length < (1ull << 63)) {
uint64_t len = hton64(iocb->payload_length);
*hdptr |= 127;
++hdptr;
@ -91,9 +87,9 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
/* Too large payload length */
return WSLAY_ERR_INVALID_ARGUMENT;
}
if(iocb->mask) {
if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
ctx->user_data) != 0) {
if (iocb->mask) {
if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
0) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->omask = 1;
@ -107,21 +103,21 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
ctx->opayloadlen = iocb->payload_length;
ctx->opayloadoff = 0;
}
if(ctx->ostate == SEND_HEADER) {
ptrdiff_t len = ctx->oheaderlimit-ctx->oheadermark;
if (ctx->ostate == SEND_HEADER) {
ptrdiff_t len = ctx->oheaderlimit - ctx->oheadermark;
ssize_t r;
int flags = 0;
if(iocb->data_length > 0) {
if (iocb->data_length > 0) {
flags |= WSLAY_MSG_MORE;
};
r = ctx->callbacks.send_callback(ctx->oheadermark, len, flags,
r = ctx->callbacks.send_callback(ctx->oheadermark, (size_t)len, flags,
ctx->user_data);
if(r > 0) {
if(r > len) {
if (r > 0) {
if (r > len) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->oheadermark += r;
if(ctx->oheadermark == ctx->oheaderlimit) {
if (ctx->oheadermark == ctx->oheaderlimit) {
ctx->ostate = SEND_PAYLOAD;
} else {
return WSLAY_ERR_WANT_WRITE;
@ -131,34 +127,34 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
return WSLAY_ERR_WANT_WRITE;
}
}
if(ctx->ostate == SEND_PAYLOAD) {
if (ctx->ostate == SEND_PAYLOAD) {
size_t totallen = 0;
if(iocb->data_length > 0) {
if(ctx->omask) {
if (iocb->data_length > 0) {
if (ctx->omask) {
uint8_t temp[4096];
const uint8_t *datamark = iocb->data,
*datalimit = iocb->data+iocb->data_length;
while(datamark < datalimit) {
size_t datalen = datalimit - datamark;
const uint8_t *writelimit = datamark+
wslay_min(sizeof(temp), datalen);
size_t writelen = writelimit-datamark;
*datalimit = iocb->data + iocb->data_length;
while (datamark < datalimit) {
size_t datalen = (size_t)(datalimit - datamark);
const uint8_t *writelimit =
datamark + wslay_min(sizeof(temp), datalen);
size_t writelen = (size_t)(writelimit - datamark);
ssize_t r;
size_t i;
for(i = 0; i < writelen; ++i) {
temp[i] = datamark[i]^ctx->omaskkey[(ctx->opayloadoff+i)%4];
for (i = 0; i < writelen; ++i) {
temp[i] = datamark[i] ^ ctx->omaskkey[(ctx->opayloadoff + i) % 4];
}
r = ctx->callbacks.send_callback(temp, writelen, 0, ctx->user_data);
if(r > 0) {
if((size_t)r > writelen) {
if (r > 0) {
if ((size_t)r > writelen) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
datamark += r;
ctx->opayloadoff += r;
totallen += r;
ctx->opayloadoff += (uint64_t)r;
totallen += (size_t)r;
}
} else {
if(totallen > 0) {
if (totallen > 0) {
break;
} else {
return WSLAY_ERR_WANT_WRITE;
@ -169,44 +165,148 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
ssize_t r;
r = ctx->callbacks.send_callback(iocb->data, iocb->data_length, 0,
ctx->user_data);
if(r > 0) {
if((size_t)r > iocb->data_length) {
if (r > 0) {
if ((size_t)r > iocb->data_length) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->opayloadoff += r;
totallen = r;
ctx->opayloadoff += (uint64_t)r;
totallen = (size_t)r;
}
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
}
if(ctx->opayloadoff == ctx->opayloadlen) {
if (ctx->opayloadoff == ctx->opayloadlen) {
ctx->ostate = PREP_HEADER;
}
return totallen;
return (ssize_t)totallen;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}
static void wslay_shift_ibuf(wslay_frame_context_ptr ctx)
{
ptrdiff_t len = ctx->ibuflimit-ctx->ibufmark;
memmove(ctx->ibuf, ctx->ibufmark, len);
ctx->ibuflimit = ctx->ibuf+len;
ssize_t wslay_frame_write(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb, uint8_t *buf,
size_t buflen, size_t *pwpayloadlen) {
uint8_t *buf_last = buf;
size_t i;
size_t hdlen;
*pwpayloadlen = 0;
if (iocb->data_length > iocb->payload_length) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
switch (ctx->ostate) {
case PREP_HEADER:
case PREP_HEADER_NOBUF:
hdlen = 2;
if (iocb->payload_length < 126) {
/* nothing to do */
} else if (iocb->payload_length < (1 << 16)) {
hdlen += 2;
} else if (iocb->payload_length < (1ull << 63)) {
hdlen += 8;
}
if (iocb->mask) {
hdlen += 4;
}
if (buflen < hdlen) {
ctx->ostate = PREP_HEADER_NOBUF;
return 0;
}
memset(buf_last, 0, hdlen);
*buf_last |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
*buf_last |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
/* Suppress stubborn gcc-10 warning */
*buf_last |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
++buf_last;
*buf_last |= (uint8_t)((uint8_t)(iocb->mask << 7) & 0x80u);
if (wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
if (iocb->payload_length < 126) {
*buf_last |= (uint8_t)iocb->payload_length;
++buf_last;
} else if (iocb->payload_length < (1 << 16)) {
uint16_t len = htons((uint16_t)iocb->payload_length);
*buf_last |= 126;
++buf_last;
memcpy(buf_last, &len, 2);
buf_last += 2;
} else if (iocb->payload_length < (1ull << 63)) {
uint64_t len = hton64(iocb->payload_length);
*buf_last |= 127;
++buf_last;
memcpy(buf_last, &len, 8);
buf_last += 8;
} else {
/* Too large payload length */
return WSLAY_ERR_INVALID_ARGUMENT;
}
if (iocb->mask) {
if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
0) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->omask = 1;
memcpy(buf_last, ctx->omaskkey, 4);
buf_last += 4;
}
}
ctx->ostate = SEND_PAYLOAD;
ctx->opayloadlen = iocb->payload_length;
ctx->opayloadoff = 0;
buflen -= (size_t)(buf_last - buf);
/* fall through */
case SEND_PAYLOAD:
if (iocb->data_length > 0) {
size_t writelen = wslay_min(buflen, iocb->data_length);
if (ctx->omask) {
for (i = 0; i < writelen; ++i) {
*buf_last++ =
iocb->data[i] ^ ctx->omaskkey[(ctx->opayloadoff + i) % 4];
}
} else {
memcpy(buf_last, iocb->data, writelen);
buf_last += writelen;
}
ctx->opayloadoff += writelen;
*pwpayloadlen = writelen;
}
if (ctx->opayloadoff == ctx->opayloadlen) {
ctx->ostate = PREP_HEADER;
}
return buf_last - buf;
default:
return WSLAY_ERR_INVALID_ARGUMENT;
}
}
static void wslay_shift_ibuf(wslay_frame_context_ptr ctx) {
ptrdiff_t len = ctx->ibuflimit - ctx->ibufmark;
memmove(ctx->ibuf, ctx->ibufmark, (size_t)len);
ctx->ibuflimit = ctx->ibuf + len;
ctx->ibufmark = ctx->ibuf;
}
static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
{
static ssize_t wslay_recv(wslay_frame_context_ptr ctx) {
ssize_t r;
if(ctx->ibufmark != ctx->ibuf) {
if (ctx->ibufmark != ctx->ibuf) {
wslay_shift_ibuf(ctx);
}
r = ctx->callbacks.recv_callback
(ctx->ibuflimit, ctx->ibuf+sizeof(ctx->ibuf)-ctx->ibuflimit,
0, ctx->user_data);
if(r > 0) {
r = ctx->callbacks.recv_callback(
ctx->ibuflimit, (size_t)(ctx->ibuf + sizeof(ctx->ibuf) - ctx->ibuflimit),
0, ctx->user_data);
if (r > 0) {
ctx->ibuflimit += r;
} else {
r = WSLAY_ERR_WANT_READ;
@ -217,17 +317,16 @@ static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
#define WSLAY_AVAIL_IBUF(ctx) ((size_t)(ctx->ibuflimit - ctx->ibufmark))
ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb)
{
struct wslay_frame_iocb *iocb) {
ssize_t r;
if(ctx->istate == RECV_HEADER1) {
if (ctx->istate == RECV_HEADER1) {
uint8_t fin, opcode, rsv, payloadlen;
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
fin = (ctx->ibufmark[0] >> 7) & 1;
@ -240,19 +339,19 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
ctx->imask = (ctx->ibufmark[0] >> 7) & 1;
payloadlen = ctx->ibufmark[0] & 0x7fu;
++ctx->ibufmark;
if(wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
if (wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
return WSLAY_ERR_PROTO;
}
if(payloadlen == 126) {
if (payloadlen == 126) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 2;
} else if(payloadlen == 127) {
} else if (payloadlen == 127) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 8;
} else {
ctx->ipayloadlen = payloadlen;
ctx->ipayloadoff = 0;
if(ctx->imask) {
if (ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
@ -260,42 +359,41 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
}
}
}
if(ctx->istate == RECV_EXT_PAYLOADLEN) {
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
if (ctx->istate == RECV_EXT_PAYLOADLEN) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
ctx->ipayloadlen = 0;
ctx->ipayloadoff = 0;
memcpy((uint8_t*)&ctx->ipayloadlen+(8-ctx->ireqread),
ctx->ibufmark, ctx->ireqread);
memcpy((uint8_t *)&ctx->ipayloadlen + (8 - ctx->ireqread), ctx->ibufmark,
ctx->ireqread);
ctx->ipayloadlen = ntoh64(ctx->ipayloadlen);
ctx->ibufmark += ctx->ireqread;
if(ctx->ireqread == 8) {
if(ctx->ipayloadlen < (1 << 16) ||
ctx->ipayloadlen & (1ull << 63)) {
if (ctx->ireqread == 8) {
if (ctx->ipayloadlen < (1 << 16) || ctx->ipayloadlen & (1ull << 63)) {
return WSLAY_ERR_PROTO;
}
} else if(ctx->ipayloadlen < 126) {
} else if (ctx->ipayloadlen < 126) {
return WSLAY_ERR_PROTO;
}
if(ctx->imask) {
if (ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
ctx->istate = RECV_PAYLOAD;
}
}
if(ctx->istate == RECV_MASKKEY) {
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if((r = wslay_recv(ctx)) <= 0) {
if (ctx->istate == RECV_MASKKEY) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
@ -303,25 +401,25 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
ctx->ibufmark += 4;
ctx->istate = RECV_PAYLOAD;
}
if(ctx->istate == RECV_PAYLOAD) {
if (ctx->istate == RECV_PAYLOAD) {
uint8_t *readlimit, *readmark;
uint64_t rempayloadlen = ctx->ipayloadlen-ctx->ipayloadoff;
if(WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
if((r = wslay_recv(ctx)) <= 0) {
uint64_t rempayloadlen = ctx->ipayloadlen - ctx->ipayloadoff;
if (WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
readmark = ctx->ibufmark;
readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen ?
ctx->ibuflimit : ctx->ibufmark+rempayloadlen;
if(ctx->imask) {
for(; ctx->ibufmark != readlimit;
++ctx->ibufmark, ++ctx->ipayloadoff) {
readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen
? ctx->ibuflimit
: ctx->ibufmark + rempayloadlen;
if (ctx->imask) {
for (; ctx->ibufmark != readlimit; ++ctx->ibufmark, ++ctx->ipayloadoff) {
ctx->ibufmark[0] ^= ctx->imaskkey[ctx->ipayloadoff % 4];
}
} else {
ctx->ibufmark = readlimit;
ctx->ipayloadoff += readlimit-readmark;
ctx->ipayloadoff += (uint64_t)(readlimit - readmark);
}
iocb->fin = ctx->iom.fin;
iocb->rsv = ctx->iom.rsv;
@ -329,12 +427,12 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
iocb->payload_length = ctx->ipayloadlen;
iocb->mask = ctx->imask;
iocb->data = readmark;
iocb->data_length = ctx->ibufmark-readmark;
if(ctx->ipayloadlen == ctx->ipayloadoff) {
iocb->data_length = (size_t)(ctx->ibufmark - readmark);
if (ctx->ipayloadlen == ctx->ipayloadoff) {
ctx->istate = RECV_HEADER1;
ctx->ireqread = 2;
}
return iocb->data_length;
return (ssize_t)iocb->data_length;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}

View File

@ -33,6 +33,7 @@
enum wslay_frame_state {
PREP_HEADER,
PREP_HEADER_NOBUF,
SEND_HEADER,
SEND_PAYLOAD,
RECV_HEADER1,

39
deps/wslay/lib/wslay_macro.h vendored Normal file
View File

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

View File

@ -26,10 +26,9 @@
#ifndef WORDS_BIGENDIAN
uint64_t wslay_byteswap64(uint64_t x)
{
uint64_t wslay_byteswap64(uint64_t x) {
uint64_t u = ntohl(x & 0xffffffffllu);
uint64_t l = ntohl(x >> 32);
uint64_t l = ntohl((uint32_t)(x >> 32));
return (u << 32) | l;
}

View File

@ -27,91 +27,51 @@
#include <string.h>
#include <assert.h>
struct wslay_queue* wslay_queue_new(void)
{
struct wslay_queue *queue = (struct wslay_queue*)malloc
(sizeof(struct wslay_queue));
if(!queue) {
return NULL;
}
queue->top = queue->tail = NULL;
return queue;
#include "wslay_macro.h"
void wslay_queue_init(struct wslay_queue *queue) {
queue->top = NULL;
queue->tail = &queue->top;
}
void wslay_queue_free(struct wslay_queue *queue)
{
if(!queue) {
return;
} else {
struct wslay_queue_cell *p = queue->top;
while(p) {
struct wslay_queue_cell *next = p->next;
free(p);
p = next;
}
free(queue);
void wslay_queue_deinit(struct wslay_queue *queue) { (void)queue; }
void wslay_queue_push(struct wslay_queue *queue,
struct wslay_queue_entry *ent) {
ent->next = NULL;
*queue->tail = ent;
queue->tail = &ent->next;
}
void wslay_queue_push_front(struct wslay_queue *queue,
struct wslay_queue_entry *ent) {
ent->next = queue->top;
queue->top = ent;
if (ent->next == NULL) {
queue->tail = &ent->next;
}
}
int wslay_queue_push(struct wslay_queue *queue, void *data)
{
struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
(sizeof(struct wslay_queue_cell));
if(!new_cell) {
return WSLAY_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = NULL;
if(queue->tail) {
queue->tail->next = new_cell;
queue->tail = new_cell;
} else {
queue->top = queue->tail = new_cell;
}
return 0;
}
int wslay_queue_push_front(struct wslay_queue *queue, void *data)
{
struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
(sizeof(struct wslay_queue_cell));
if(!new_cell) {
return WSLAY_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = queue->top;
queue->top = new_cell;
if(!queue->tail) {
queue->tail = queue->top;
}
return 0;
}
void wslay_queue_pop(struct wslay_queue *queue)
{
struct wslay_queue_cell *top = queue->top;
assert(top);
queue->top = top->next;
if(top == queue->tail) {
queue->tail = NULL;
}
free(top);
}
void* wslay_queue_top(struct wslay_queue *queue)
{
void wslay_queue_pop(struct wslay_queue *queue) {
assert(queue->top);
return queue->top->data;
queue->top = queue->top->next;
if (queue->top == NULL) {
queue->tail = &queue->top;
}
}
void* wslay_queue_tail(struct wslay_queue *queue)
{
assert(queue->tail);
return queue->tail->data;
struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue) {
assert(queue->top);
return queue->top;
}
int wslay_queue_empty(struct wslay_queue *queue)
{
struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue) {
assert(queue->top);
return wslay_struct_of(queue->tail, struct wslay_queue_entry, next);
}
int wslay_queue_empty(struct wslay_queue *queue) {
assert(queue->top || queue->tail == &queue->top);
return queue->top == NULL;
}

View File

@ -31,23 +31,23 @@
#include <wslay/wslay.h>
struct wslay_queue_cell {
void *data;
struct wslay_queue_cell *next;
struct wslay_queue_entry {
struct wslay_queue_entry *next;
};
struct wslay_queue {
struct wslay_queue_cell *top;
struct wslay_queue_cell *tail;
struct wslay_queue_entry *top;
struct wslay_queue_entry **tail;
};
struct wslay_queue* wslay_queue_new(void);
void wslay_queue_free(struct wslay_queue *queue);
int wslay_queue_push(struct wslay_queue *queue, void *data);
int wslay_queue_push_front(struct wslay_queue *queue, void *data);
void wslay_queue_init(struct wslay_queue *queue);
void wslay_queue_deinit(struct wslay_queue *queue);
void wslay_queue_push(struct wslay_queue *queue, struct wslay_queue_entry *ent);
void wslay_queue_push_front(struct wslay_queue *queue,
struct wslay_queue_entry *ent);
void wslay_queue_pop(struct wslay_queue *queue);
void* wslay_queue_top(struct wslay_queue *queue);
void* wslay_queue_tail(struct wslay_queue *queue);
struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue);
struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue);
int wslay_queue_empty(struct wslay_queue *queue);
#endif /* WSLAY_QUEUE_H */

View File

@ -30,35 +30,27 @@
#include "wslay_event_test.h"
#include "wslay_queue_test.h"
static int init_suite1(void)
{
return 0;
}
static int init_suite1(void) { return 0; }
static int clean_suite1(void)
{
return 0;
}
static int clean_suite1(void) { return 0; }
int main(void) {
CU_pSuite pSuite = NULL;
unsigned int num_tests_failed;
int main(void)
{
CU_pSuite pSuite = NULL;
unsigned int num_tests_failed;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
/* add a suite to the registry */
pSuite = CU_add_suite("libwslay_TestSuite", init_suite1, clean_suite1);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
/* add a suite to the registry */
pSuite = CU_add_suite("libwslay_TestSuite", init_suite1, clean_suite1);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
/* add the tests to the suite */
if(!CU_add_test(pSuite, "wslay_frame_context_init",
/* add the tests to the suite */
if (!CU_add_test(pSuite, "wslay_frame_context_init",
test_wslay_frame_context_init) ||
!CU_add_test(pSuite, "wslay_frame_recv", test_wslay_frame_recv) ||
!CU_add_test(pSuite, "wslay_frame_recv_1byte",
@ -90,8 +82,23 @@ int main(void)
test_wslay_frame_send_too_large_payload) ||
!CU_add_test(pSuite, "wslay_frame_send_ctrl_frame_too_large_payload",
test_wslay_frame_send_ctrl_frame_too_large_payload) ||
!CU_add_test(pSuite, "wslay_frame_write", test_wslay_frame_write) ||
!CU_add_test(pSuite, "wslay_frame_write_fragmented",
test_wslay_frame_write_fragmented) ||
!CU_add_test(pSuite, "wslay_frame_write_interleaved_ctrl_frame",
test_wslay_frame_write_interleaved_ctrl_frame) ||
!CU_add_test(pSuite, "wslay_frame_write_1byte_masked",
test_wslay_frame_write_1byte_masked) ||
!CU_add_test(pSuite, "wslay_frame_write_zero_payloadlen",
test_wslay_frame_write_zero_payloadlen) ||
!CU_add_test(pSuite, "wslay_frame_write_too_large_payload",
test_wslay_frame_write_too_large_payload) ||
!CU_add_test(pSuite, "wslay_frame_write_ctrl_frame_too_large_payload",
test_wslay_frame_write_ctrl_frame_too_large_payload) ||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg",
test_wslay_event_send_fragmented_msg) ||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_empty_data",
test_wslay_event_send_fragmented_msg_empty_data) ||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_with_ctrl",
test_wslay_event_send_fragmented_msg_with_ctrl) ||
!CU_add_test(pSuite, "wslay_event_send_fragmented_msg_with_rsv1",
@ -124,20 +131,32 @@ int main(void)
test_wslay_event_message_too_big) ||
!CU_add_test(pSuite, "wslay_event_config_set_allowed_rsv_bits",
test_wslay_event_config_set_allowed_rsv_bits) ||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg",
test_wslay_event_write_fragmented_msg) ||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_empty_data",
test_wslay_event_write_fragmented_msg_empty_data) ||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_with_ctrl",
test_wslay_event_write_fragmented_msg_with_ctrl) ||
!CU_add_test(pSuite, "wslay_event_write_fragmented_msg_with_rsv1",
test_wslay_event_write_fragmented_msg_with_rsv1) ||
!CU_add_test(pSuite, "wslay_event_write_msg_with_rsv1",
test_wslay_event_write_msg_with_rsv1) ||
!CU_add_test(pSuite, "wslay_event_write_ctrl_msg_first",
test_wslay_event_write_ctrl_msg_first) ||
!CU_add_test(pSuite, "wslay_queue", test_wslay_queue)) {
CU_cleanup_registry();
return CU_get_error();
}
CU_cleanup_registry();
return CU_get_error();
}
/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_tests_failed = CU_get_number_of_tests_failed();
CU_cleanup_registry();
if (CU_get_error() == CUE_SUCCESS) {
return (int)num_tests_failed;
} else {
printf("CUnit Error: %s\n", CU_get_error_msg());
return CU_get_error();
}
/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_tests_failed = CU_get_number_of_tests_failed();
CU_cleanup_registry();
if (CU_get_error() == CUE_SUCCESS) {
return (int)num_tests_failed;
} else {
printf("CUnit Error: %s\n", CU_get_error_msg());
return CU_get_error();
}
}

View File

@ -32,8 +32,8 @@
struct scripted_data_feed {
uint8_t data[8192];
uint8_t* datamark;
uint8_t* datalimit;
uint8_t *datamark;
uint8_t *datalimit;
size_t feedseq[8192];
size_t seqidx;
};
@ -49,44 +49,43 @@ struct my_user_data {
};
static void scripted_data_feed_init(struct scripted_data_feed *df,
const uint8_t *data, size_t data_length)
{
const uint8_t *data, size_t data_length) {
memset(df, 0, sizeof(struct scripted_data_feed));
memcpy(df->data, data, data_length);
if (data_length) {
memcpy(df->data, data, data_length);
}
df->datamark = df->data;
df->datalimit = df->data+data_length;
df->datalimit = df->data + data_length;
df->feedseq[0] = data_length;
}
static ssize_t scripted_read_callback
(wslay_event_context_ptr ctx,
uint8_t *data, size_t len, const union wslay_event_msg_source *source,
int *eof, void *user_data)
{
struct scripted_data_feed *df = (struct scripted_data_feed*)source->data;
static ssize_t
scripted_read_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
const union wslay_event_msg_source *source, int *eof,
void *user_data) {
struct scripted_data_feed *df = (struct scripted_data_feed *)source->data;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
if (wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
if(df->datamark == df->datalimit) {
if (df->datamark == df->datalimit) {
*eof = 1;
}
return wlen;
}
static ssize_t scripted_recv_callback(wslay_event_context_ptr ctx,
uint8_t* data, size_t len, int flags,
void *user_data)
{
struct scripted_data_feed *df = ((struct my_user_data*)user_data)->df;
uint8_t *data, size_t len, int flags,
void *user_data) {
struct scripted_data_feed *df = ((struct my_user_data *)user_data)->df;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
if (wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
@ -96,45 +95,38 @@ static ssize_t scripted_recv_callback(wslay_event_context_ptr ctx,
static ssize_t accumulator_send_callback(wslay_event_context_ptr ctx,
const uint8_t *buf, size_t len,
int flags, void* user_data)
{
struct accumulator *acc = ((struct my_user_data*)user_data)->acc;
assert(acc->length+len < sizeof(acc->buf));
memcpy(acc->buf+acc->length, buf, len);
int flags, void *user_data) {
struct accumulator *acc = ((struct my_user_data *)user_data)->acc;
assert(acc->length + len < sizeof(acc->buf));
memcpy(acc->buf + acc->length, buf, len);
acc->length += len;
return len;
}
static ssize_t one_accumulator_send_callback(wslay_event_context_ptr ctx,
const uint8_t *buf, size_t len,
int flags, void* user_data)
{
struct accumulator *acc = ((struct my_user_data*)user_data)->acc;
int flags, void *user_data) {
struct accumulator *acc = ((struct my_user_data *)user_data)->acc;
assert(len > 0);
memcpy(acc->buf+acc->length, buf, 1);
memcpy(acc->buf + acc->length, buf, 1);
acc->length += 1;
return 1;
}
static ssize_t fail_recv_callback(wslay_event_context_ptr ctx,
uint8_t* data, size_t len, int flags,
void *user_data)
{
static ssize_t fail_recv_callback(wslay_event_context_ptr ctx, uint8_t *data,
size_t len, int flags, void *user_data) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
static ssize_t fail_send_callback(wslay_event_context_ptr ctx,
const uint8_t *buf, size_t len, int flags,
void* user_data)
{
void *user_data) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
void test_wslay_event_send_fragmented_msg(void)
{
void test_wslay_event_send_fragmented_msg(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
@ -142,11 +134,8 @@ void test_wslay_event_send_fragmented_msg(void)
const char msg[] = "Hello";
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {
0x01, 0x03, 0x48, 0x65, 0x6c,
0x80, 0x02, 0x6c, 0x6f
};
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
const uint8_t ans[] = {0x01, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
@ -166,8 +155,33 @@ void test_wslay_event_send_fragmented_msg(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_send_fragmented_msg_with_ctrl(void)
{
void test_wslay_event_send_fragmented_msg_empty_data(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {0x81, 0x00};
scripted_data_feed_init(&df, NULL, 0);
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
memset(&acc, 0, sizeof(acc));
ud.acc = &acc;
wslay_event_context_server_init(&ctx, &callbacks, &ud);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.source.data = &df;
arg.read_callback = scripted_read_callback;
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
CU_ASSERT(0 == wslay_event_send(ctx));
CU_ASSERT_EQUAL(2, acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
wslay_event_context_free(ctx);
}
void test_wslay_event_send_fragmented_msg_with_ctrl(void) {
int i;
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
@ -178,11 +192,11 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
struct wslay_event_fragmented_msg arg;
struct wslay_event_msg ctrl_arg;
const uint8_t ans[] = {
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x89, 0x00, /* unmasked ping */
0x80, 0x02, 0x6c, 0x6f /* "lo" */
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x89, 0x00, /* unmasked ping */
0x80, 0x02, 0x6c, 0x6f /* "lo" */
};
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
@ -205,7 +219,7 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
ctrl_arg.msg_length = 0;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &ctrl_arg));
CU_ASSERT(2 == wslay_event_get_queued_msg_count(ctx));
for(i = 0; i < 10; ++i) {
for (i = 0; i < 10; ++i) {
CU_ASSERT(0 == wslay_event_send(ctx));
}
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
@ -214,8 +228,7 @@ void test_wslay_event_send_fragmented_msg_with_ctrl(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_send_fragmented_msg_with_rsv1(void)
{
void test_wslay_event_send_fragmented_msg_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
@ -223,11 +236,8 @@ void test_wslay_event_send_fragmented_msg_with_rsv1(void)
const char msg[] = "Hello";
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {
0x41, 0x03, 0x48, 0x65, 0x6c,
0x80, 0x02, 0x6c, 0x6f
};
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg)-1);
const uint8_t ans[] = {0x41, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
@ -249,8 +259,7 @@ void test_wslay_event_send_fragmented_msg_with_rsv1(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_send_msg_with_rsv1(void)
{
void test_wslay_event_send_msg_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
@ -258,7 +267,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
const char msg[] = "Hello";
struct wslay_event_msg arg;
const uint8_t ans[] = {
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
memset(&callbacks, 0, sizeof(callbacks));
@ -270,7 +279,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.msg = (const uint8_t*)msg;
arg.msg = (const uint8_t *)msg;
arg.msg_length = 5;
CU_ASSERT(0 == wslay_event_queue_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
CU_ASSERT(0 == wslay_event_send(ctx));
@ -279,8 +288,7 @@ void test_wslay_event_send_msg_with_rsv1(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_send_ctrl_msg_first(void)
{
void test_wslay_event_send_ctrl_msg_first(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
@ -288,8 +296,8 @@ void test_wslay_event_send_ctrl_msg_first(void)
const char msg[] = "Hello";
struct wslay_event_msg arg;
const uint8_t ans[] = {
0x89, 0x00, /* unmasked ping */
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
0x89, 0x00, /* unmasked ping */
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
@ -302,7 +310,7 @@ void test_wslay_event_send_ctrl_msg_first(void)
arg.msg_length = 0;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.msg = (const uint8_t*)msg;
arg.msg = (const uint8_t *)msg;
arg.msg_length = 5;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
CU_ASSERT(0 == wslay_event_send(ctx));
@ -311,8 +319,7 @@ void test_wslay_event_send_ctrl_msg_first(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_send_ctrl_msg_with_rsv1(void)
{
void test_wslay_event_send_ctrl_msg_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct wslay_event_msg arg;
@ -331,15 +338,14 @@ void test_wslay_event_send_ctrl_msg_with_rsv1(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_queue_close(void)
{
void test_wslay_event_queue_close(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
const char msg[] = "H";
const uint8_t ans[] = {
0x88, 0x03, 0x03, 0xf1, 0x48 /* "H" */
0x88, 0x03, 0x03, 0xf1, 0x48 /* "H" */
};
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
@ -347,7 +353,7 @@ void test_wslay_event_queue_close(void)
ud.acc = &acc;
wslay_event_context_server_init(&ctx, &callbacks, &ud);
CU_ASSERT(0 == wslay_event_queue_close(ctx, WSLAY_CODE_MESSAGE_TOO_BIG,
(const uint8_t*)msg, 1));
(const uint8_t *)msg, 1));
CU_ASSERT(0 == wslay_event_send(ctx));
CU_ASSERT(5 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
@ -355,14 +361,13 @@ void test_wslay_event_queue_close(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_queue_close_without_code(void)
{
void test_wslay_event_queue_close_without_code(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
const uint8_t ans[] = { 0x88, 0x00 };
struct wslay_event_msg ping = { WSLAY_PING, NULL, 0 };
const uint8_t ans[] = {0x88, 0x00};
struct wslay_event_msg ping = {WSLAY_PING, NULL, 0};
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
memset(&acc, 0, sizeof(acc));
@ -375,19 +380,17 @@ void test_wslay_event_queue_close_without_code(void)
CU_ASSERT(2 == acc.length);
CU_ASSERT(0 == memcmp(ans, acc.buf, acc.length));
CU_ASSERT(1 == wslay_event_get_close_sent(ctx));
CU_ASSERT(WSLAY_CODE_NO_STATUS_RCVD ==
wslay_event_get_status_code_sent(ctx));
CU_ASSERT(WSLAY_CODE_NO_STATUS_RCVD == wslay_event_get_status_code_sent(ctx));
wslay_event_context_free(ctx);
}
void test_wslay_event_recv_close_without_code(void)
{
void test_wslay_event_recv_close_without_code(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
const uint8_t msg[] = { 0x88u, 0x00 };
const uint8_t msg[] = {0x88u, 0x00};
struct scripted_data_feed df;
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
callbacks.recv_callback = scripted_recv_callback;
ud.df = &df;
@ -399,23 +402,22 @@ void test_wslay_event_recv_close_without_code(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_reply_close(void)
{
void test_wslay_event_reply_close(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
/* Masked close frame with code = 1009, reason = "Hello" */
const uint8_t msg[] = { 0x88u, 0x87u, 0x00u, 0x00u, 0x00u, 0x00u,
0x03, 0xf1, /* 1009 */
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
const uint8_t msg[] = {
0x88u, 0x87u, 0x00u, 0x00u, 0x00u, 0x00u, 0x03, 0xf1, /* 1009 */
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
const uint8_t ans[] = { 0x88u, 0x07u,
0x03, 0xf1, /* 1009 */
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
const uint8_t ans[] = {
0x88u, 0x07u, 0x03, 0xf1, /* 1009 */
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
struct scripted_data_feed df;
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.recv_callback = scripted_recv_callback;
@ -445,8 +447,7 @@ void test_wslay_event_reply_close(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_no_more_msg(void)
{
void test_wslay_event_no_more_msg(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
@ -456,8 +457,7 @@ void test_wslay_event_no_more_msg(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_callback_failure(void)
{
void test_wslay_event_callback_failure(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
@ -472,9 +472,8 @@ void test_wslay_event_callback_failure(void)
static void no_buffering_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
if(arg->opcode == WSLAY_PING) {
void *user_data) {
if (arg->opcode == WSLAY_PING) {
CU_ASSERT(3 == arg->msg_length);
CU_ASSERT(0 == memcmp("Foo", arg->msg, arg->msg_length));
} else {
@ -483,18 +482,17 @@ static void no_buffering_callback(wslay_event_context_ptr ctx,
}
}
void test_wslay_event_no_buffering(void)
{
void test_wslay_event_no_buffering(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
const uint8_t msg[] = {
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x89, 0x03, 0x46, 0x6f, 0x6f, /* ping with "Foo" */
0x80, 0x02, 0x6c, 0x6f, /* "lo" */
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x89, 0x03, 0x46, 0x6f, 0x6f, /* ping with "Foo" */
0x80, 0x02, 0x6c, 0x6f, /* "lo" */
};
struct scripted_data_feed df;
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
ud.df = &df;
callbacks.recv_callback = scripted_recv_callback;
@ -510,35 +508,33 @@ void test_wslay_event_no_buffering(void)
static void
text_rsv1_on_msg_recv_callback(wslay_event_context_ptr ctx,
const struct wslay_event_on_msg_recv_arg *arg,
void *user_data)
{
void *user_data) {
CU_ASSERT(WSLAY_TEXT_FRAME == arg->opcode);
CU_ASSERT(WSLAY_RSV1_BIT == arg->rsv);
}
void test_wslay_event_recv_text_frame_with_rsv1(void)
{
void test_wslay_event_recv_text_frame_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
const uint8_t msg[] = {
0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00 // "Hello" pm-deflate
0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00 // "Hello" pm-deflate
};
const uint8_t fragmented[] = {
0x41, 0x03, 0xf2, 0x48, 0xcd, // First fragment
0x80, 0x04, 0xc9, 0xc9, 0x07, 0x00 // Second fragment, RSV1 bit off
0x41, 0x03, 0xf2, 0x48, 0xcd, // First fragment
0x80, 0x04, 0xc9, 0xc9, 0x07, 0x00 // Second fragment, RSV1 bit off
};
const uint8_t bad_fragment[] = {
0x41, 0x03, 0xf2, 0x48, 0xcd,
0xc0, 0x04, 0xc9, 0xc9, 0x07, 0x00 // RSV1 bit on
0x41, 0x03, 0xf2, 0x48, 0xcd, 0xc0,
0x04, 0xc9, 0xc9, 0x07, 0x00 // RSV1 bit on
};
const uint8_t pingmsg[] = {
0xc9, 0x03, 0x46, 0x6f, 0x6f /* ping with "Foo" */
0xc9, 0x03, 0x46, 0x6f, 0x6f /* ping with "Foo" */
};
struct scripted_data_feed df;
/* Message marked with RSV1 should skip UTF-8 validation */
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
ud.df = &df;
callbacks.recv_callback = scripted_recv_callback;
@ -551,7 +547,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
/* UTF-8 validation is skipped for continuation frames if the
* initial frame was marked with RSV1 bit */
scripted_data_feed_init(&df, (const uint8_t*)fragmented, sizeof(fragmented));
scripted_data_feed_init(&df, (const uint8_t *)fragmented, sizeof(fragmented));
memset(&callbacks, 0, sizeof(callbacks));
ud.df = &df;
callbacks.recv_callback = scripted_recv_callback;
@ -563,7 +559,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
wslay_event_context_free(ctx);
/* disallow RSV1 */
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
wslay_event_context_client_init(&ctx, &callbacks, &ud);
CU_ASSERT(0 == wslay_event_recv(ctx));
/* Close frame must be queued */
@ -571,8 +567,8 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
wslay_event_context_free(ctx);
/* RSV1 is not allowed in continuation frame */
scripted_data_feed_init(&df, (const uint8_t*)bad_fragment,
sizeof(bad_fragment));
scripted_data_feed_init(&df, (const uint8_t *)bad_fragment,
sizeof(bad_fragment));
wslay_event_context_client_init(&ctx, &callbacks, &ud);
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
CU_ASSERT(0 == wslay_event_recv(ctx));
@ -581,7 +577,7 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
wslay_event_context_free(ctx);
/* RSV1 is not allowed in ping frame */
scripted_data_feed_init(&df, (const uint8_t*)pingmsg, sizeof(pingmsg));
scripted_data_feed_init(&df, (const uint8_t *)pingmsg, sizeof(pingmsg));
wslay_event_context_client_init(&ctx, &callbacks, &ud);
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
CU_ASSERT(0 == wslay_event_recv(ctx));
@ -590,21 +586,21 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_frame_too_big(void)
{
void test_wslay_event_frame_too_big(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
/* Masked text frame */
const uint8_t msg[] = { 0x81, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
const uint8_t msg[] = {
0x81, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
const uint8_t ans[] = { 0x88, 0x02,
0x03, 0xf1 /* 1009 */
const uint8_t ans[] = {
0x88, 0x02, 0x03, 0xf1 /* 1009 */
};
struct scripted_data_feed df;
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.recv_callback = scripted_recv_callback;
@ -623,23 +619,23 @@ void test_wslay_event_frame_too_big(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_message_too_big(void)
{
void test_wslay_event_message_too_big(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct my_user_data ud;
struct accumulator acc;
/* Masked text 2 frames */
const uint8_t msg[] = { 0x01, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f, /* "Hello" */
0x80, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
const uint8_t msg[] = {
0x01, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f, /* "Hello" */
0x80, 0x85, 0x00, 0x00, 0x00, 0x00,
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
const uint8_t ans[] = { 0x88, 0x02,
0x03, 0xf1 /* 1009 */
const uint8_t ans[] = {
0x88, 0x02, 0x03, 0xf1 /* 1009 */
};
struct scripted_data_feed df;
scripted_data_feed_init(&df, (const uint8_t*)msg, sizeof(msg));
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg));
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.recv_callback = scripted_recv_callback;
@ -658,8 +654,7 @@ void test_wslay_event_message_too_big(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_config_set_allowed_rsv_bits(void)
{
void test_wslay_event_config_set_allowed_rsv_bits(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
@ -683,3 +678,164 @@ void test_wslay_event_config_set_allowed_rsv_bits(void)
wslay_event_context_free(ctx);
}
void test_wslay_event_write_fragmented_msg(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
const char msg[] = "Hello";
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {0x01, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
uint8_t buf[1024];
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
wslay_event_context_server_init(&ctx, &callbacks, NULL);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.source.data = &df;
arg.read_callback = scripted_read_callback;
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}
void test_wslay_event_write_fragmented_msg_empty_data(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {0x81, 0x00};
uint8_t buf[1024];
scripted_data_feed_init(&df, NULL, 0);
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
wslay_event_context_server_init(&ctx, &callbacks, NULL);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.source.data = &df;
arg.read_callback = scripted_read_callback;
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}
void test_wslay_event_write_fragmented_msg_with_ctrl(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
const char msg[] = "Hello";
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
struct wslay_event_msg ctrl_arg;
const uint8_t ans[] = {
0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x89, 0x00, /* unmasked ping */
0x80, 0x02, 0x6c, 0x6f /* "lo" */
};
uint8_t buf[1024];
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
wslay_event_context_server_init(&ctx, &callbacks, NULL);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.source.data = &df;
arg.read_callback = scripted_read_callback;
CU_ASSERT(0 == wslay_event_queue_fragmented_msg(ctx, &arg));
CU_ASSERT(1 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(0 == wslay_event_get_queued_msg_length(ctx));
CU_ASSERT(4 == wslay_event_write(ctx, buf, 4));
memset(&ctrl_arg, 0, sizeof(ctrl_arg));
ctrl_arg.opcode = WSLAY_PING;
ctrl_arg.msg_length = 0;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &ctrl_arg));
CU_ASSERT(2 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(7 == wslay_event_write(ctx, buf + 4, sizeof(buf) - 4));
CU_ASSERT(0 == wslay_event_get_queued_msg_count(ctx));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}
void test_wslay_event_write_fragmented_msg_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
const char msg[] = "Hello";
struct scripted_data_feed df;
struct wslay_event_fragmented_msg arg;
const uint8_t ans[] = {0x41, 0x03, 0x48, 0x65, 0x6c, 0x80, 0x02, 0x6c, 0x6f};
uint8_t buf[1024];
scripted_data_feed_init(&df, (const uint8_t *)msg, sizeof(msg) - 1);
df.feedseq[0] = 3;
df.feedseq[1] = 2;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
wslay_event_context_server_init(&ctx, &callbacks, NULL);
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.source.data = &df;
arg.read_callback = scripted_read_callback;
CU_ASSERT(0 ==
wslay_event_queue_fragmented_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}
void test_wslay_event_write_msg_with_rsv1(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
const char msg[] = "Hello";
struct wslay_event_msg arg;
const uint8_t ans[] = {
0xc1, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
uint8_t buf[1024];
memset(&callbacks, 0, sizeof(callbacks));
wslay_event_context_server_init(&ctx, &callbacks, NULL);
wslay_event_config_set_allowed_rsv_bits(ctx, WSLAY_RSV1_BIT);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.msg = (const uint8_t *)msg;
arg.msg_length = 5;
CU_ASSERT(0 == wslay_event_queue_msg_ex(ctx, &arg, WSLAY_RSV1_BIT));
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}
void test_wslay_event_write_ctrl_msg_first(void) {
wslay_event_context_ptr ctx;
struct wslay_event_callbacks callbacks;
const char msg[] = "Hello";
struct wslay_event_msg arg;
const uint8_t ans[] = {
0x89, 0x00, /* unmasked ping */
0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
};
uint8_t buf[1024];
memset(&callbacks, 0, sizeof(callbacks));
wslay_event_context_server_init(&ctx, &callbacks, NULL);
memset(&arg, 0, sizeof(arg));
arg.opcode = WSLAY_PING;
arg.msg_length = 0;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
arg.opcode = WSLAY_TEXT_FRAME;
arg.msg = (const uint8_t *)msg;
arg.msg_length = 5;
CU_ASSERT(0 == wslay_event_queue_msg(ctx, &arg));
CU_ASSERT(sizeof(ans) == wslay_event_write(ctx, buf, sizeof(buf)));
CU_ASSERT(0 == memcmp(ans, buf, sizeof(ans)));
wslay_event_context_free(ctx);
}

View File

@ -26,6 +26,7 @@
#define WSLAY_EVENT_TEST_H
void test_wslay_event_send_fragmented_msg(void);
void test_wslay_event_send_fragmented_msg_empty_data(void);
void test_wslay_event_send_fragmented_msg_with_ctrl(void);
void test_wslay_event_send_fragmented_msg_with_rsv1(void);
void test_wslay_event_send_msg_with_rsv1(void);
@ -42,5 +43,11 @@ void test_wslay_event_recv_text_frame_with_rsv1(void);
void test_wslay_event_frame_too_big(void);
void test_wslay_event_message_too_big(void);
void test_wslay_event_config_set_allowed_rsv_bits(void);
void test_wslay_event_write_fragmented_msg(void);
void test_wslay_event_write_fragmented_msg_empty_data(void);
void test_wslay_event_write_fragmented_msg_with_ctrl(void);
void test_wslay_event_write_fragmented_msg_with_rsv1(void);
void test_wslay_event_write_msg_with_rsv1(void);
void test_wslay_event_write_ctrl_msg_first(void);
#endif /* WSLAY_EVENT_TEST_H */

View File

@ -30,8 +30,7 @@
#include "wslay_frame.h"
void test_wslay_frame_context_init(void)
{
void test_wslay_frame_context_init(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
int user_data;
@ -42,30 +41,30 @@ void test_wslay_frame_context_init(void)
struct scripted_data_feed {
uint8_t data[8192];
uint8_t* datamark;
uint8_t* datalimit;
uint8_t *datamark;
uint8_t *datalimit;
size_t feedseq[8192];
size_t seqidx;
};
static void scripted_data_feed_init(struct scripted_data_feed *df,
uint8_t *data, size_t data_length)
{
uint8_t *data, size_t data_length) {
memset(df, 0, sizeof(struct scripted_data_feed));
memcpy(df->data, data, data_length);
if (data_length) {
memcpy(df->data, data, data_length);
}
df->datamark = df->data;
df->datalimit = df->data+data_length;
df->datalimit = df->data + data_length;
df->feedseq[0] = data_length;
}
static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
void *user_data)
{
struct scripted_data_feed *df = (struct scripted_data_feed*)user_data;
static ssize_t scripted_recv_callback(uint8_t *data, size_t len, int flags,
void *user_data) {
struct scripted_data_feed *df = (struct scripted_data_feed *)user_data;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
if (wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
@ -73,14 +72,13 @@ static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
return wlen;
}
static ssize_t scripted_send_callback(const uint8_t* data, size_t len,
int flags, void *user_data)
{
struct scripted_data_feed *df = (struct scripted_data_feed*)user_data;
static ssize_t scripted_send_callback(const uint8_t *data, size_t len,
int flags, void *user_data) {
struct scripted_data_feed *df = (struct scripted_data_feed *)user_data;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(df->datamark, data, wlen);
df->datamark += wlen;
if(wlen <= len) {
if (wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
@ -88,17 +86,14 @@ static ssize_t scripted_send_callback(const uint8_t* data, size_t len,
return wlen;
}
void test_wslay_frame_recv(void)
{
void test_wslay_frame_recv(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
/* Masked text frame containing "Hello" */
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
0x4du, 0x51u, 0x58u };
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
scripted_data_feed_init(&df, msg, sizeof(msg));
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -114,28 +109,25 @@ void test_wslay_frame_recv(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_1byte(void)
{
void test_wslay_frame_recv_1byte(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
size_t i;
/* Masked text frame containing "Hello" */
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
0x4du, 0x51u, 0x58u };
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
scripted_data_feed_init(&df, msg, sizeof(msg));
for(i = 0; i < sizeof(msg); ++i) {
for (i = 0; i < sizeof(msg); ++i) {
df.feedseq[i] = 1;
}
wslay_frame_context_init(&ctx, &callbacks, &df);
for(i = 0; i < 4; ++i) {
for (i = 0; i < 4; ++i) {
CU_ASSERT(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
}
for(i = 0; i < 5; ++i) {
for (i = 0; i < 5; ++i) {
CU_ASSERT(1 == wslay_frame_recv(ctx, &iocb));
CU_ASSERT_EQUAL(1, iocb.fin);
CU_ASSERT_EQUAL(0, iocb.rsv);
@ -143,24 +135,21 @@ void test_wslay_frame_recv_1byte(void)
CU_ASSERT_EQUAL(5, iocb.payload_length);
CU_ASSERT_EQUAL(1, iocb.mask);
CU_ASSERT_EQUAL(1, iocb.data_length);
CU_ASSERT_EQUAL(msg[6+i]^msg[2+i%4], iocb.data[0]);
CU_ASSERT_EQUAL(msg[6 + i] ^ msg[2 + i % 4], iocb.data[0]);
}
CU_ASSERT(WSLAY_ERR_WANT_READ == wslay_frame_recv(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_fragmented(void)
{
void test_wslay_frame_recv_fragmented(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg[] = { 0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
uint8_t msg[] = {0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 5;
df.feedseq[1] = 4;
@ -187,23 +176,19 @@ void test_wslay_frame_recv_fragmented(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_interleaved_ctrl_frame(void)
{
void test_wslay_frame_recv_interleaved_ctrl_frame(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg[] = { 0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
/* ping with "Hello" */
0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
uint8_t msg[] = {0x01, 0x03, 0x48, 0x65, 0x6c, /* "Hel" */
/* ping with "Hello" */
0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x80, 0x02, 0x6c,
0x6f}; /* "lo" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 5;
df.feedseq[1] = 7,
df.feedseq[2] = 4;
df.feedseq[1] = 7, df.feedseq[2] = 4;
wslay_frame_context_init(&ctx, &callbacks, &df);
CU_ASSERT(3 == wslay_frame_recv(ctx, &iocb));
@ -236,16 +221,13 @@ void test_wslay_frame_recv_interleaved_ctrl_frame(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_zero_payloadlen(void)
{
void test_wslay_frame_recv_zero_payloadlen(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg[] = { 0x81, 0x00 }; /* "" */
uint8_t msg[] = {0x81, 0x00}; /* "" */
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = 2;
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -261,15 +243,12 @@ void test_wslay_frame_recv_zero_payloadlen(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_too_large_payload(void)
{
void test_wslay_frame_recv_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
uint8_t msg[] = { 0x81, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t msg[] = {0x81, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -278,15 +257,12 @@ void test_wslay_frame_recv_too_large_payload(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_ctrl_frame_too_large_payload(void)
{
void test_wslay_frame_recv_ctrl_frame_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
uint8_t msg[] = { 0x88, 0x7e };
uint8_t msg[] = {0x88, 0x7e};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -295,15 +271,12 @@ void test_wslay_frame_recv_ctrl_frame_too_large_payload(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_minimum_ext_payload16(void)
{
void test_wslay_frame_recv_minimum_ext_payload16(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
uint8_t msg[] = { 0x81, 0x7e, 0x00, 0x7d };
uint8_t msg[] = {0x81, 0x7e, 0x00, 0x7d};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -312,15 +285,12 @@ void test_wslay_frame_recv_minimum_ext_payload16(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_recv_minimum_ext_payload64(void)
{
void test_wslay_frame_recv_minimum_ext_payload64(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { NULL,
scripted_recv_callback,
NULL };
struct wslay_frame_callbacks callbacks = {NULL, scripted_recv_callback, NULL};
struct scripted_data_feed df;
struct wslay_frame_iocb iocb;
uint8_t msg[] = { 0x81, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
uint8_t msg[] = {0x81, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
scripted_data_feed_init(&df, msg, sizeof(msg));
df.feedseq[0] = sizeof(msg);
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -335,34 +305,29 @@ struct accumulator {
};
static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
int flags, void* user_data)
{
struct accumulator *acc = (struct accumulator*)user_data;
assert(acc->length+len < sizeof(acc->buf));
memcpy(acc->buf+acc->length, buf, len);
int flags, void *user_data) {
struct accumulator *acc = (struct accumulator *)user_data;
assert(acc->length + len < sizeof(acc->buf));
memcpy(acc->buf + acc->length, buf, len);
acc->length += len;
return len;
}
static int static_genmask_callback(uint8_t *buf, size_t len,
void* user_data)
{
static const uint8_t makskey[] = { 0x37u, 0xfau, 0x21u, 0x3du };
static int static_genmask_callback(uint8_t *buf, size_t len, void *user_data) {
static const uint8_t makskey[] = {0x37u, 0xfau, 0x21u, 0x3du};
memcpy(buf, makskey, 4);
return 0;
}
void test_wslay_frame_send(void)
{
void test_wslay_frame_send(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
NULL,
static_genmask_callback };
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
static_genmask_callback};
struct accumulator acc;
struct wslay_frame_iocb iocb;
/* Masked text frame containing "Hello" */
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
0x4du, 0x51u, 0x58u };
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
@ -370,7 +335,7 @@ void test_wslay_frame_send(void)
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 1;
iocb.payload_length = 5;
iocb.data = (const uint8_t*)"Hello";
iocb.data = (const uint8_t *)"Hello";
iocb.data_length = 5;
CU_ASSERT(5 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg), acc.length);
@ -379,17 +344,15 @@ void test_wslay_frame_send(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_fragmented(void)
{
void test_wslay_frame_send_fragmented(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
NULL,
static_genmask_callback };
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
static_genmask_callback};
struct accumulator acc;
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg1[] = { 0x01, 0x03, 0x48, 0x65, 0x6c }; /* "Hel" */
uint8_t msg2[] = { 0x80, 0x02, 0x6c, 0x6f }; /* "lo" */
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c}; /* "Hel" */
uint8_t msg2[] = {0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
@ -397,7 +360,7 @@ void test_wslay_frame_send_fragmented(void)
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = 3;
iocb.data = (const uint8_t*)"Hel";
iocb.data = (const uint8_t *)"Hel";
iocb.data_length = 3;
CU_ASSERT(3 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
@ -407,7 +370,7 @@ void test_wslay_frame_send_fragmented(void)
iocb.fin = 1;
iocb.opcode = WSLAY_CONTINUATION_FRAME;
iocb.payload_length = 2;
iocb.data = (const uint8_t*)"lo";
iocb.data = (const uint8_t *)"lo";
iocb.data_length = 2;
CU_ASSERT(2 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg2), acc.length);
@ -416,21 +379,19 @@ void test_wslay_frame_send_fragmented(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_interleaved_ctrl_frame(void)
{
void test_wslay_frame_send_interleaved_ctrl_frame(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
NULL,
static_genmask_callback };
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
static_genmask_callback};
struct accumulator acc;
struct wslay_frame_iocb iocb;
/* Unmasked message */
/* text with "Hel", with fin = 0 */
uint8_t msg1[] = { 0x01, 0x03, 0x48, 0x65, 0x6c };
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c};
/* ping with "Hello" */
uint8_t msg2[] = { 0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f };
uint8_t msg2[] = {0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f};
/* text with "lo", continuation frame for msg1, with fin = 1 */
uint8_t msg3[] = { 0x80, 0x02, 0x6c, 0x6f };
uint8_t msg3[] = {0x80, 0x02, 0x6c, 0x6f};
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
acc.length = 0;
@ -438,7 +399,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = 3;
iocb.data = (const uint8_t*)"Hel";
iocb.data = (const uint8_t *)"Hel";
iocb.data_length = 3;
CU_ASSERT(3 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg1), acc.length);
@ -448,7 +409,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
iocb.fin = 1;
iocb.opcode = WSLAY_PING;
iocb.payload_length = 5;
iocb.data = (const uint8_t*)"Hello";
iocb.data = (const uint8_t *)"Hello";
iocb.data_length = 5;
CU_ASSERT(5 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg2), acc.length);
@ -458,7 +419,7 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
iocb.fin = 1;
iocb.opcode = WSLAY_CONTINUATION_FRAME;
iocb.payload_length = 2;
iocb.data = (const uint8_t*)"lo";
iocb.data = (const uint8_t *)"lo";
iocb.data_length = 2;
CU_ASSERT(2 == wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(sizeof(msg3), acc.length);
@ -467,21 +428,19 @@ void test_wslay_frame_send_interleaved_ctrl_frame(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_1byte_masked(void)
{
void test_wslay_frame_send_1byte_masked(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { scripted_send_callback,
NULL,
static_genmask_callback };
struct wslay_frame_callbacks callbacks = {scripted_send_callback, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Masked text frame containing "Hello" */
uint8_t msg[] = { 0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du, 0x7fu, 0x9fu,
0x4du, 0x51u, 0x58u };
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
uint8_t hello[] = "Hello";
struct scripted_data_feed df;
size_t i;
scripted_data_feed_init(&df, NULL, 0);
for(i = 0; i < sizeof(msg); ++i) {
for (i = 0; i < sizeof(msg); ++i) {
df.feedseq[i] = 1;
}
wslay_frame_context_init(&ctx, &callbacks, &df);
@ -491,8 +450,8 @@ void test_wslay_frame_send_1byte_masked(void)
iocb.mask = 1;
iocb.payload_length = 5;
iocb.data = hello;
iocb.data_length = sizeof(hello)-1;
for(i = 0; i < 5; ++i) {
iocb.data_length = sizeof(hello) - 1;
for (i = 0; i < 5; ++i) {
CU_ASSERT_EQUAL(WSLAY_ERR_WANT_WRITE, wslay_frame_send(ctx, &iocb));
}
CU_ASSERT_EQUAL(5, wslay_frame_send(ctx, &iocb));
@ -500,16 +459,14 @@ void test_wslay_frame_send_1byte_masked(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_zero_payloadlen(void)
{
void test_wslay_frame_send_zero_payloadlen(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = { accumulator_send_callback,
NULL,
static_genmask_callback };
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
static_genmask_callback};
struct accumulator acc;
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg[] = { 0x81, 0x00 }; /* "" */
uint8_t msg[] = {0x81, 0x00}; /* "" */
acc.length = 0;
wslay_frame_context_init(&ctx, &callbacks, &acc);
memset(&iocb, 0, sizeof(iocb));
@ -525,8 +482,7 @@ void test_wslay_frame_send_zero_payloadlen(void)
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_too_large_payload(void)
{
void test_wslay_frame_send_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
@ -536,14 +492,12 @@ void test_wslay_frame_send_too_large_payload(void)
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = UINT64_MAX;
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT,
wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT, wslay_frame_send(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_send_ctrl_frame_too_large_payload(void)
{
void test_wslay_frame_send_ctrl_frame_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
@ -553,8 +507,213 @@ void test_wslay_frame_send_ctrl_frame_too_large_payload(void)
iocb.opcode = WSLAY_PING;
iocb.mask = 0;
iocb.payload_length = 1024;
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT,
wslay_frame_send(ctx, &iocb));
CU_ASSERT_EQUAL(WSLAY_ERR_INVALID_ARGUMENT, wslay_frame_send(ctx, &iocb));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = {NULL, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Masked text frame containing "Hello" */
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 1;
iocb.payload_length = 5;
iocb.data = (const uint8_t *)"Hello";
iocb.data_length = 5;
CU_ASSERT(11 ==
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(iocb.data_length == wpayloadlen);
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_fragmented(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = {NULL, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c}; /* "Hel" */
uint8_t msg2[] = {0x80, 0x02, 0x6c, 0x6f}; /* "lo" */
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 0;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = 3;
iocb.data = (const uint8_t *)"Hel";
iocb.data_length = 3;
CU_ASSERT(5 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(3 == wpayloadlen);
CU_ASSERT(memcmp(msg1, buf, sizeof(msg1)) == 0);
iocb.fin = 1;
iocb.opcode = WSLAY_CONTINUATION_FRAME;
iocb.payload_length = 2;
iocb.data = (const uint8_t *)"lo";
iocb.data_length = 2;
CU_ASSERT(4 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(2 == wpayloadlen);
CU_ASSERT(memcmp(msg2, buf, sizeof(msg2)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_interleaved_ctrl_frame(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = {NULL, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Unmasked message */
/* text with "Hel", with fin = 0 */
uint8_t msg1[] = {0x01, 0x03, 0x48, 0x65, 0x6c};
/* ping with "Hello" */
uint8_t msg2[] = {0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f};
/* text with "lo", continuation frame for msg1, with fin = 1 */
uint8_t msg3[] = {0x80, 0x02, 0x6c, 0x6f};
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 0;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = 3;
iocb.data = (const uint8_t *)"Hel";
iocb.data_length = 3;
CU_ASSERT(5 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(3 == wpayloadlen);
CU_ASSERT(memcmp(msg1, buf, sizeof(msg1)) == 0);
iocb.fin = 1;
iocb.opcode = WSLAY_PING;
iocb.payload_length = 5;
iocb.data = (const uint8_t *)"Hello";
iocb.data_length = 5;
CU_ASSERT(7 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(5 == wpayloadlen);
CU_ASSERT(memcmp(msg2, buf, sizeof(msg2)) == 0);
iocb.fin = 1;
iocb.opcode = WSLAY_CONTINUATION_FRAME;
iocb.payload_length = 2;
iocb.data = (const uint8_t *)"lo";
iocb.data_length = 2;
CU_ASSERT(4 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(2 == wpayloadlen);
CU_ASSERT(memcmp(msg3, buf, sizeof(msg3)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_1byte_masked(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = {NULL, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Masked text frame containing "Hello" */
uint8_t msg[] = {0x81u, 0x85u, 0x37u, 0xfau, 0x21u, 0x3du,
0x7fu, 0x9fu, 0x4du, 0x51u, 0x58u};
uint8_t hello[] = "Hello";
size_t i;
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 1;
iocb.payload_length = 5;
iocb.data = hello;
iocb.data_length = sizeof(hello) - 1;
CU_ASSERT_EQUAL(6, wslay_frame_write(ctx, &iocb, buf, 6, &wpayloadlen));
CU_ASSERT(0 == wpayloadlen);
for (i = 0; i < 5; ++i) {
CU_ASSERT_EQUAL(
1, wslay_frame_write(ctx, &iocb, buf + 6 + i, 1, &wpayloadlen));
CU_ASSERT(1 == wpayloadlen);
++iocb.data;
--iocb.data_length;
}
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_zero_payloadlen(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks = {NULL, NULL,
static_genmask_callback};
struct wslay_frame_iocb iocb;
/* Unmasked message */
uint8_t msg[] = {0x81, 0x00}; /* "" */
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = 0;
iocb.data_length = 0;
CU_ASSERT(2 == wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
CU_ASSERT(0 == wpayloadlen);
CU_ASSERT(memcmp(msg, buf, sizeof(msg)) == 0);
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = WSLAY_TEXT_FRAME;
iocb.mask = 0;
iocb.payload_length = UINT64_MAX;
CU_ASSERT_EQUAL(
WSLAY_ERR_INVALID_ARGUMENT,
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
wslay_frame_context_free(ctx);
}
void test_wslay_frame_write_ctrl_frame_too_large_payload(void) {
wslay_frame_context_ptr ctx;
struct wslay_frame_callbacks callbacks;
struct wslay_frame_iocb iocb;
uint8_t buf[1024];
size_t wpayloadlen;
wslay_frame_context_init(&ctx, &callbacks, NULL);
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = WSLAY_PING;
iocb.mask = 0;
iocb.payload_length = 1024;
CU_ASSERT_EQUAL(
WSLAY_ERR_INVALID_ARGUMENT,
wslay_frame_write(ctx, &iocb, buf, sizeof(buf), &wpayloadlen));
wslay_frame_context_free(ctx);
}

View File

@ -42,5 +42,12 @@ void test_wslay_frame_send_1byte_masked(void);
void test_wslay_frame_send_zero_payloadlen(void);
void test_wslay_frame_send_too_large_payload(void);
void test_wslay_frame_send_ctrl_frame_too_large_payload(void);
void test_wslay_frame_write(void);
void test_wslay_frame_write_fragmented(void);
void test_wslay_frame_write_interleaved_ctrl_frame(void);
void test_wslay_frame_write_1byte_masked(void);
void test_wslay_frame_write_zero_payloadlen(void);
void test_wslay_frame_write_too_large_payload(void);
void test_wslay_frame_write_ctrl_frame_too_large_payload(void);
#endif /* WSLAY_FRAME_TEST_H */

View File

@ -27,33 +27,49 @@
#include <CUnit/CUnit.h>
#include "wslay_queue.h"
#include "wslay_macro.h"
void test_wslay_queue(void)
{
int ints[] = { 1, 2, 3, 4, 5 };
struct queue_entry {
struct wslay_queue_entry qe;
int value;
};
void test_wslay_queue(void) {
struct queue_entry ents[] = {
{{0}, 1}, {{0}, 2}, {{0}, 3}, {{0}, 4}, {{0}, 5},
};
int i;
struct wslay_queue *queue = wslay_queue_new();
CU_ASSERT(wslay_queue_empty(queue));
for(i = 0; i < 5; ++i) {
wslay_queue_push(queue, &ints[i]);
CU_ASSERT_EQUAL(ints[0], *(int*)(wslay_queue_top(queue)));
CU_ASSERT(!wslay_queue_empty(queue));
struct wslay_queue queue;
wslay_queue_init(&queue);
CU_ASSERT(wslay_queue_empty(&queue));
for (i = 0; i < 5; ++i) {
wslay_queue_push(&queue, &ents[i].qe);
CU_ASSERT_EQUAL(ents[0].value, wslay_struct_of(wslay_queue_top(&queue),
struct queue_entry, qe)
->value);
CU_ASSERT(!wslay_queue_empty(&queue));
}
for(i = 0; i < 5; ++i) {
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
wslay_queue_pop(queue);
for (i = 0; i < 5; ++i) {
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
struct queue_entry, qe)
->value);
wslay_queue_pop(&queue);
}
CU_ASSERT(wslay_queue_empty(queue));
CU_ASSERT(wslay_queue_empty(&queue));
for(i = 0; i < 5; ++i) {
wslay_queue_push_front(queue, &ints[i]);
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
CU_ASSERT(!wslay_queue_empty(queue));
for (i = 0; i < 5; ++i) {
wslay_queue_push_front(&queue, &ents[i].qe);
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
struct queue_entry, qe)
->value);
CU_ASSERT(!wslay_queue_empty(&queue));
}
for(i = 4; i >= 0; --i) {
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_queue_top(queue)));
wslay_queue_pop(queue);
for (i = 4; i >= 0; --i) {
CU_ASSERT_EQUAL(ents[i].value, wslay_struct_of(wslay_queue_top(&queue),
struct queue_entry, qe)
->value);
wslay_queue_pop(&queue);
}
CU_ASSERT(wslay_queue_empty(queue));
wslay_queue_free(queue);
CU_ASSERT(wslay_queue_empty(&queue));
wslay_queue_deinit(&queue);
}

View File

@ -28,19 +28,18 @@
#include "wslay_stack.h"
void test_wslay_stack()
{
int ints[] = { 1, 2, 3, 4, 5 };
void test_wslay_stack() {
int ints[] = {1, 2, 3, 4, 5};
int i;
struct wslay_stack *stack = wslay_stack_new();
CU_ASSERT(wslay_stack_empty(stack));
for(i = 0; i < 5; ++i) {
for (i = 0; i < 5; ++i) {
wslay_stack_push(stack, &ints[i]);
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_stack_top(stack)));
CU_ASSERT_EQUAL(ints[i], *(int *)(wslay_stack_top(stack)));
CU_ASSERT(!wslay_stack_empty(stack));
}
for(i = 4; i >= 0; --i) {
CU_ASSERT_EQUAL(ints[i], *(int*)(wslay_stack_top(stack)));
for (i = 4; i >= 0; --i) {
CU_ASSERT_EQUAL(ints[i], *(int *)(wslay_stack_top(stack)));
wslay_stack_pop(stack);
}
CU_ASSERT(wslay_stack_empty(stack));