mirror of https://github.com/aria2/aria2
Update wslay
parent
a151b5bcef
commit
63f6ed726e
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -92,22 +91,22 @@ 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);
|
||||
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);
|
||||
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()));
|
||||
|
@ -117,20 +116,19 @@ std::string sha1(const std::string& src)
|
|||
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;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string create_acceptkey(const std::string& clientkey)
|
||||
{
|
||||
std::string create_acceptkey(const std::string &clientkey) {
|
||||
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
return base64(sha1(s));
|
||||
}
|
||||
|
@ -147,9 +145,8 @@ public:
|
|||
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,9 +155,7 @@ 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,
|
||||
|
@ -168,34 +163,29 @@ public:
|
|||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_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()
|
||||
{
|
||||
virtual int on_read_event() {
|
||||
if (wslay_event_recv(ctx_) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
virtual int on_write_event()
|
||||
{
|
||||
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
|
||||
|
@ -203,44 +193,29 @@ public:
|
|||
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)
|
||||
{
|
||||
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) {
|
||||
|
@ -254,8 +229,7 @@ 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)
|
||||
{
|
||||
int flags, void *user_data) {
|
||||
EchoWebSocketHandler *sv = (EchoWebSocketHandler *)user_data;
|
||||
ssize_t r = sv->recv_data(data, len, flags);
|
||||
if (r == -1) {
|
||||
|
@ -273,12 +247,9 @@ 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)
|
||||
{
|
||||
void *user_data) {
|
||||
if (!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {
|
||||
arg->opcode, arg->msg, arg->msg_length
|
||||
};
|
||||
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
|
||||
wslay_event_queue_msg(ctx, &msgarg);
|
||||
}
|
||||
}
|
||||
|
@ -290,23 +261,19 @@ public:
|
|||
resheaders_("HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: "+accept_key+"\r\n"
|
||||
"Sec-WebSocket-Accept: " +
|
||||
accept_key +
|
||||
"\r\n"
|
||||
"\r\n"),
|
||||
off_(0)
|
||||
{}
|
||||
virtual ~HttpHandshakeSendHandler()
|
||||
{
|
||||
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()
|
||||
{
|
||||
virtual int on_read_event() { return 0; }
|
||||
virtual int on_write_event() {
|
||||
while (1) {
|
||||
size_t len = resheaders_.size() - off_;
|
||||
if (len == 0) {
|
||||
|
@ -314,7 +281,8 @@ public:
|
|||
}
|
||||
ssize_t r;
|
||||
while ((r = write(fd_, resheaders_.c_str() + off_, len)) == -1 &&
|
||||
errno == EINTR);
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
break;
|
||||
|
@ -328,24 +296,11 @@ 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()
|
||||
{
|
||||
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;
|
||||
|
@ -354,6 +309,7 @@ public:
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
std::string headers_;
|
||||
|
@ -363,22 +319,19 @@ private:
|
|||
|
||||
class HttpHandshakeRecvHandler : public EventHandler {
|
||||
public:
|
||||
HttpHandshakeRecvHandler(int fd)
|
||||
: fd_(fd)
|
||||
{}
|
||||
virtual ~HttpHandshakeRecvHandler()
|
||||
{
|
||||
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);
|
||||
while ((r = read(fd_, buf, sizeof(buf))) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
break;
|
||||
|
@ -413,28 +366,12 @@ public:
|
|||
}
|
||||
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()
|
||||
{
|
||||
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;
|
||||
|
@ -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()
|
||||
{
|
||||
virtual int on_read_event() {
|
||||
if (cfd_ != -1) {
|
||||
close(cfd_);
|
||||
}
|
||||
while((cfd_ = accept(fd_, 0, 0)) == -1 && errno == EINTR);
|
||||
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()
|
||||
{
|
||||
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) {
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val,
|
||||
(socklen_t)sizeof(val)) == -1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
@ -507,13 +426,13 @@ 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;
|
||||
|
@ -528,8 +447,7 @@ int ctl_epollev(int epollfd, int op, EventHandler *handler)
|
|||
return epoll_ctl(epollfd, op, handler->fd(), &ev);
|
||||
}
|
||||
|
||||
void reactor(int sfd)
|
||||
{
|
||||
void reactor(int sfd) {
|
||||
std::set<EventHandler *> handlers;
|
||||
ListenEventHandler *listen_handler = new ListenEventHandler(sfd);
|
||||
handlers.insert(listen_handler);
|
||||
|
@ -586,8 +504,7 @@ void reactor(int sfd)
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " PORT" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -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;
|
||||
|
@ -102,15 +101,16 @@ 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);
|
||||
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);
|
||||
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,8 +148,7 @@ 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);
|
||||
|
@ -166,20 +163,16 @@ 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;
|
||||
|
||||
|
@ -188,17 +181,11 @@ http_header_find_field_value(char *header, char *field_name, char *value)
|
|||
|
||||
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);
|
||||
|
@ -239,20 +226,22 @@ 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);
|
||||
sizeof(header) - header_length)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("read");
|
||||
return -1;
|
||||
|
@ -260,7 +249,7 @@ int http_handshake(int fd)
|
|||
fprintf(stderr, "HTTP Handshake: Got EOF");
|
||||
return -1;
|
||||
} else {
|
||||
header_length += r;
|
||||
header_length += (size_t)r;
|
||||
if (header_length >= 4 &&
|
||||
memcmp(header + header_length - 4, "\r\n\r\n", 4) == 0) {
|
||||
break;
|
||||
|
@ -273,13 +262,16 @@ int http_handshake(int fd)
|
|||
|
||||
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) {
|
||||
(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);
|
||||
for (; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend)
|
||||
;
|
||||
if (keyhdend - keyhdstart != 24) {
|
||||
printf("%s\n", keyhdstart);
|
||||
fprintf(stderr, "HTTP Handshake: Invalid value in Sec-WebSocket-Key");
|
||||
|
@ -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);
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("write");
|
||||
return -1;
|
||||
} else {
|
||||
res_header_sent += r;
|
||||
res_header_sent += (size_t)r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -315,10 +309,8 @@ 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)
|
||||
{
|
||||
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;
|
||||
|
@ -327,7 +319,8 @@ ssize_t send_callback(wslay_event_context_ptr ctx,
|
|||
sflags |= MSG_MORE;
|
||||
}
|
||||
#endif // MSG_MORE
|
||||
while((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR);
|
||||
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);
|
||||
|
@ -338,12 +331,13 @@ 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)
|
||||
{
|
||||
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);
|
||||
(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);
|
||||
|
@ -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,
|
||||
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) {
|
||||
(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
|
||||
};
|
||||
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
|
||||
wslay_event_queue_msg(ctx, &msgarg);
|
||||
}
|
||||
}
|
||||
|
@ -377,18 +369,11 @@ 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
|
||||
};
|
||||
recv_callback, send_callback, NULL, NULL, NULL,
|
||||
NULL, on_msg_recv_callback};
|
||||
struct Session session = {fd};
|
||||
int val = 1;
|
||||
struct pollfd event;
|
||||
|
@ -400,8 +385,8 @@ int communicate(int fd)
|
|||
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;
|
||||
}
|
||||
|
@ -415,7 +400,8 @@ int communicate(int fd)
|
|||
*/
|
||||
while (wslay_event_want_read(ctx) || wslay_event_want_write(ctx)) {
|
||||
int r;
|
||||
while((r = poll(&event, 1, -1)) == -1 && errno == EINTR);
|
||||
while ((r = poll(&event, 1, -1)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("poll");
|
||||
res = -1;
|
||||
|
@ -451,11 +437,11 @@ 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)
|
||||
{
|
||||
static void __attribute__((noreturn)) serve(int sfd) {
|
||||
while (1) {
|
||||
int fd;
|
||||
while((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
while ((fd = accept(sfd, NULL, NULL)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (fd == -1) {
|
||||
perror("accept");
|
||||
} else {
|
||||
|
@ -464,7 +450,7 @@ void serve(int sfd)
|
|||
perror("fork");
|
||||
close(fd);
|
||||
} else if (r == 0) {
|
||||
int r = communicate(fd);
|
||||
r = communicate(fd);
|
||||
shutdown(fd, SHUT_WR);
|
||||
close(fd);
|
||||
if (r == 0) {
|
||||
|
@ -477,8 +463,7 @@ void serve(int sfd)
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
struct sigaction act;
|
||||
int sfd;
|
||||
if (argc < 2) {
|
||||
|
|
|
@ -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;
|
||||
|
@ -72,7 +71,8 @@ int connect_to(const char *host, const char *service)
|
|||
continue;
|
||||
}
|
||||
while ((r = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
|
||||
errno == EINTR);
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
|
@ -83,22 +83,22 @@ 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);
|
||||
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);
|
||||
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()));
|
||||
|
@ -108,12 +108,11 @@ std::string sha1(const std::string& src)
|
|||
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()));
|
||||
std::string res(&dst[0], &dst[dstlen]);
|
||||
|
@ -121,8 +120,7 @@ std::string base64(const std::string& src)
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string create_acceptkey(const std::string& clientkey)
|
||||
{
|
||||
std::string create_acceptkey(const std::string &clientkey) {
|
||||
std::string s = clientkey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
return base64(sha1(s));
|
||||
}
|
||||
|
@ -131,29 +129,17 @@ 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")
|
||||
{
|
||||
: 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
|
||||
|
@ -161,11 +147,11 @@ public:
|
|||
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)
|
||||
{
|
||||
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);
|
||||
|
@ -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_write()
|
||||
{
|
||||
return wslay_event_want_write(ctx_);
|
||||
}
|
||||
int fd() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
void get_random(uint8_t *buf, size_t len)
|
||||
{
|
||||
bool want_read() { return wslay_event_want_read(ctx_); }
|
||||
bool want_write() { return wslay_event_want_write(ctx_); }
|
||||
int fd() const { return fd_; }
|
||||
void get_random(uint8_t *buf, size_t len) {
|
||||
dev_urand_.read((char *)buf, len);
|
||||
}
|
||||
void set_callbacks(const struct wslay_event_callbacks *callbacks)
|
||||
{
|
||||
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,10 +185,8 @@ 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)
|
||||
{
|
||||
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) {
|
||||
|
@ -226,8 +200,7 @@ 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)
|
||||
{
|
||||
int flags, void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
ssize_t r = ws->recv_data(data, len, flags);
|
||||
if (r == -1) {
|
||||
|
@ -243,17 +216,14 @@ ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len,
|
|||
return r;
|
||||
}
|
||||
|
||||
ssize_t feed_body_callback
|
||||
(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags,
|
||||
void *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)
|
||||
{
|
||||
void *user_data) {
|
||||
WebSocketClient *ws = (WebSocketClient *)user_data;
|
||||
ws->get_random(buf, len);
|
||||
return 0;
|
||||
|
@ -261,35 +231,31 @@ int genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, 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)
|
||||
{
|
||||
void *user_data) {
|
||||
if (!wslay_is_ctrl_frame(arg->opcode)) {
|
||||
struct wslay_event_msg msgarg = {
|
||||
arg->opcode, arg->msg, arg->msg_length
|
||||
};
|
||||
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)
|
||||
{
|
||||
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()) {
|
||||
ssize_t r;
|
||||
size_t len = reqheader.size() - off;
|
||||
while((r = write(fd, reqheader.c_str()+off, len)) == -1 && errno == EINTR);
|
||||
while ((r = write(fd, reqheader.c_str() + off, len)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
perror("write");
|
||||
return -1;
|
||||
|
@ -299,12 +265,12 @@ 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) {
|
||||
ssize_t r;
|
||||
while((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR);
|
||||
while ((r = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -320,8 +286,7 @@ 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);
|
||||
|
@ -329,8 +294,7 @@ std::string get_random16()
|
|||
}
|
||||
|
||||
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),
|
||||
|
@ -367,8 +331,7 @@ int http_handshake(int fd, const char *host, const char *service,
|
|||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
|
@ -384,8 +347,7 @@ void ctl_epollev(int epollfd, int op, WebSocketClient& ws)
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -401,8 +363,8 @@ int communicate(const char *host, const char *service, const char *path,
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
@ -442,8 +404,7 @@ 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,
|
||||
|
@ -451,8 +412,7 @@ int get_casecnt(const char *host, const char *service)
|
|||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
get_casecnt_on_msg_recv_callback
|
||||
};
|
||||
get_casecnt_on_msg_recv_callback};
|
||||
if (communicate(host, service, "/getCaseCount", &callbacks) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -465,8 +425,7 @@ int get_casecnt(const char *host, const char *service)
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -474,18 +433,14 @@ int run_testcase(const char *host, const char *service, int casenum)
|
|||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
on_msg_recv_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,
|
||||
recv_callback, send_callback, genmask_callback,
|
||||
NULL, /* on_frame_recv_start_callback */
|
||||
NULL, /* on_frame_recv_callback */
|
||||
NULL, /* on_frame_recv_end_callback */
|
||||
|
@ -494,8 +449,7 @@ int update_reports(const char *host, const char *service)
|
|||
return communicate(host, service, "/updateReports?&agent=wslay", &callbacks);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " HOST SERV" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
@ -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,8 +316,8 @@ 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,
|
||||
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 {
|
||||
|
@ -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,
|
||||
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
|
@ -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 */
|
||||
|
|
|
@ -34,9 +34,8 @@
|
|||
|
||||
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));
|
||||
void *user_data) {
|
||||
*ctx = malloc(sizeof(struct wslay_frame_context));
|
||||
if (*ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -50,33 +49,30 @@ 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)
|
||||
{
|
||||
struct wslay_frame_iocb *iocb) {
|
||||
if (iocb->data_length > iocb->payload_length) {
|
||||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (ctx->ostate == PREP_HEADER) {
|
||||
uint8_t *hdptr = ctx->oheader;
|
||||
memset(ctx->oheader, 0, sizeof(ctx->oheader));
|
||||
*hdptr |= (iocb->fin << 7) & 0x80u;
|
||||
*hdptr |= (iocb->rsv << 4) & 0x70u;
|
||||
*hdptr |= iocb->opcode & 0xfu;
|
||||
*hdptr |= (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;
|
||||
*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;
|
||||
*hdptr |= (uint8_t)iocb->payload_length;
|
||||
++hdptr;
|
||||
} else if (iocb->payload_length < (1 << 16)) {
|
||||
uint16_t len = htons(iocb->payload_length);
|
||||
uint16_t len = htons((uint16_t)iocb->payload_length);
|
||||
*hdptr |= 126;
|
||||
++hdptr;
|
||||
memcpy(hdptr, &len, 2);
|
||||
|
@ -92,8 +88,8 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
return WSLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (iocb->mask) {
|
||||
if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
|
||||
ctx->user_data) != 0) {
|
||||
if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
|
||||
0) {
|
||||
return WSLAY_ERR_INVALID_CALLBACK;
|
||||
} else {
|
||||
ctx->omask = 1;
|
||||
|
@ -114,7 +110,7 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
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) {
|
||||
|
@ -139,10 +135,10 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
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;
|
||||
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) {
|
||||
|
@ -154,8 +150,8 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
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) {
|
||||
|
@ -173,8 +169,8 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
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;
|
||||
|
@ -184,27 +180,131 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
|
|||
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)
|
||||
{
|
||||
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, len);
|
||||
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) {
|
||||
wslay_shift_ibuf(ctx);
|
||||
}
|
||||
r = ctx->callbacks.recv_callback
|
||||
(ctx->ibuflimit, ctx->ibuf+sizeof(ctx->ibuf)-ctx->ibuflimit,
|
||||
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;
|
||||
|
@ -217,8 +317,7 @@ 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) {
|
||||
uint8_t fin, opcode, rsv, payloadlen;
|
||||
|
@ -271,13 +370,12 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
|||
}
|
||||
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->ipayloadlen < (1 << 16) || ctx->ipayloadlen & (1ull << 63)) {
|
||||
return WSLAY_ERR_PROTO;
|
||||
}
|
||||
} else if (ctx->ipayloadlen < 126) {
|
||||
|
@ -312,16 +410,16 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
|
|||
}
|
||||
}
|
||||
readmark = ctx->ibufmark;
|
||||
readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen ?
|
||||
ctx->ibuflimit : ctx->ibufmark+rempayloadlen;
|
||||
readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen
|
||||
? ctx->ibuflimit
|
||||
: ctx->ibufmark + rempayloadlen;
|
||||
if (ctx->imask) {
|
||||
for(; ctx->ibufmark != readlimit;
|
||||
++ctx->ibufmark, ++ctx->ipayloadoff) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
enum wslay_frame_state {
|
||||
PREP_HEADER,
|
||||
PREP_HEADER_NOBUF,
|
||||
SEND_HEADER,
|
||||
SEND_PAYLOAD,
|
||||
RECV_HEADER1,
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
}
|
||||
free(queue);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -30,19 +30,11 @@
|
|||
#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)
|
||||
{
|
||||
int main(void) {
|
||||
CU_pSuite pSuite = NULL;
|
||||
unsigned int num_tests_failed;
|
||||
|
||||
|
@ -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,6 +131,18 @@ 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();
|
||||
|
|
|
@ -49,20 +49,20 @@ 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));
|
||||
if (data_length) {
|
||||
memcpy(df->data, data, data_length);
|
||||
}
|
||||
df->datamark = df->data;
|
||||
df->datalimit = df->data + data_length;
|
||||
df->feedseq[0] = data_length;
|
||||
}
|
||||
|
||||
static ssize_t scripted_read_callback
|
||||
(wslay_event_context_ptr ctx,
|
||||
uint8_t *data, size_t len, const union wslay_event_msg_source *source,
|
||||
int *eof, void *user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -80,8 +80,7 @@ static ssize_t scripted_read_callback
|
|||
|
||||
static ssize_t scripted_recv_callback(wslay_event_context_ptr ctx,
|
||||
uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -96,8 +95,7 @@ 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)
|
||||
{
|
||||
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);
|
||||
|
@ -107,8 +105,7 @@ static ssize_t accumulator_send_callback(wslay_event_context_ptr ctx,
|
|||
|
||||
static ssize_t one_accumulator_send_callback(wslay_event_context_ptr ctx,
|
||||
const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -116,25 +113,20 @@ static ssize_t one_accumulator_send_callback(wslay_event_context_ptr ctx,
|
|||
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,10 +134,7 @@ 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
|
||||
};
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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,10 +236,7 @@ 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
|
||||
};
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,8 +338,7 @@ 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;
|
||||
|
@ -355,8 +361,7 @@ 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;
|
||||
|
@ -375,13 +380,11 @@ 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;
|
||||
|
@ -399,19 +402,18 @@ 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 */
|
||||
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 */
|
||||
const uint8_t ans[] = {
|
||||
0x88u, 0x07u, 0x03, 0xf1, /* 1009 */
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f /* "Hello" */
|
||||
};
|
||||
struct scripted_data_feed df;
|
||||
|
@ -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,8 +472,7 @@ 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)
|
||||
{
|
||||
void *user_data) {
|
||||
if (arg->opcode == WSLAY_PING) {
|
||||
CU_ASSERT(3 == arg->msg_length);
|
||||
CU_ASSERT(0 == memcmp("Foo", arg->msg, arg->msg_length));
|
||||
|
@ -483,8 +482,7 @@ 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;
|
||||
|
@ -510,14 +508,12 @@ 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;
|
||||
|
@ -529,8 +525,8 @@ void test_wslay_event_recv_text_frame_with_rsv1(void)
|
|||
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" */
|
||||
|
@ -590,18 +586,18 @@ 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,
|
||||
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));
|
||||
|
@ -623,20 +619,20 @@ 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,
|
||||
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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
@ -49,18 +48,18 @@ struct scripted_data_feed {
|
|||
};
|
||||
|
||||
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));
|
||||
if (data_length) {
|
||||
memcpy(df->data, data, data_length);
|
||||
}
|
||||
df->datamark = df->data;
|
||||
df->datalimit = df->data + data_length;
|
||||
df->feedseq[0] = data_length;
|
||||
}
|
||||
|
||||
static ssize_t scripted_recv_callback(uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -74,8 +73,7 @@ static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
|
|||
}
|
||||
|
||||
static ssize_t scripted_send_callback(const uint8_t *data, size_t len,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -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,18 +109,15 @@ 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) {
|
||||
df.feedseq[i] = 1;
|
||||
|
@ -150,12 +142,9 @@ void test_wslay_frame_recv_1byte(void)
|
|||
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 */
|
||||
|
@ -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" */
|
||||
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,12 +221,9 @@ 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 */
|
||||
|
@ -261,12 +243,9 @@ 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};
|
||||
|
@ -278,12 +257,9 @@ 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};
|
||||
|
@ -295,12 +271,9 @@ 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};
|
||||
|
@ -312,12 +285,9 @@ 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};
|
||||
|
@ -335,8 +305,7 @@ struct accumulator {
|
|||
};
|
||||
|
||||
static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
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);
|
||||
|
@ -344,25 +313,21 @@ static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int static_genmask_callback(uint8_t *buf, size_t len,
|
||||
void* user_data)
|
||||
{
|
||||
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,
|
||||
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;
|
||||
|
@ -379,11 +344,9 @@ 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,
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
|
@ -416,11 +379,9 @@ 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,
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb iocb;
|
||||
|
@ -467,16 +428,14 @@ 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,
|
||||
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;
|
||||
|
@ -500,11 +459,9 @@ 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,
|
||||
struct wslay_frame_callbacks callbacks = {accumulator_send_callback, NULL,
|
||||
static_genmask_callback};
|
||||
struct accumulator acc;
|
||||
struct wslay_frame_iocb 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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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));
|
||||
struct wslay_queue queue;
|
||||
wslay_queue_init(&queue);
|
||||
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));
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
|
||||
#include "wslay_stack.h"
|
||||
|
||||
void test_wslay_stack()
|
||||
{
|
||||
void test_wslay_stack() {
|
||||
int ints[] = {1, 2, 3, 4, 5};
|
||||
int i;
|
||||
struct wslay_stack *stack = wslay_stack_new();
|
||||
|
|
Loading…
Reference in New Issue