zaphoyd / websocketpp Goto Github PK
View Code? Open in Web Editor NEWC++ websocket client/server library
Home Page: http://www.zaphoyd.com/websocketpp
License: Other
C++ websocket client/server library
Home Page: http://www.zaphoyd.com/websocketpp
License: Other
During the switch from read until CRLF to frame lengths frames or partial frames can discarded if they were sent in the same TCP packet as the handshake.
Presently UTF8 validation is done on a per frame basis. A frame is read and then checked. True fast UTF8 fail would fail as soon as the first bad byte was read. Doing this would require a different setup for reading from ASIO so it will be low priority for now. THis might need to be done in the future anyways, in particular if a streaming api is ever needed.
Chat server example doesn't work with the new API
is required by the spec
see section 10.6
Per section 4.4 the server should return a list of version headers in the response if the handshake fails due to the client's advertised version being unsupported.
Per Section 5.2: Note that in all case the minimal number of bytes MUST be used to encode the length, for example the length of a 124 byte long string can't be encoded as the sequence 126, 0, 124.
WebSocket++ always sends compliant values, it does not validate that received values are compliant
As you say for Frame Interface:
WebSocket++ does not queue messages. As such only one send operation can be occuring at once.
So errors in all chat_server_handler functions:
I tried to run under Windows XP debug version of client/server chat which builded with Misrosoft Visual Studio 2008 with boost 1.47.0.
And after getting in client:
[server] Welcome, use the /alias command to set a name, /help for a list of other commands.
[server] 127.0.0.1:1279 has joined the chat.
I get debug exception 'vector iterator not dereferencable' in BOOST_ASIO_ENABLE_BUFFER_DEBUGGING check in win_iocp_operation::complete(win_iocp_io_service& owner,
const boost::system::error_code& ec = boost::system::error_code(),
std::size_t bytes_transferred = 0)
in chatserver.exe.
Maybe to add in WebSocket++ queue messages?
file: uri.cpp
method: the uri class constructor
problem description: if multiple clients call the endpoint's connect method in parallel, then all of them try to instance the static boost::regex expression. The result is an assert and crash somewhere inside of the boost::regex class.
fix:
- static const boost::regex expression("(ws|wss)://([^/:\[]+|[[0-9a-fA-F:.]+])(:\d{1,5})?(/[^#]*)?");
const boost::regex expression("(ws|wss)://([^/:\[]+|[[0-9a-fA-F:.]+])(:\d{1,5})?(/[^#]*)?");
has changed to Origin in protocol 13
file: data.hpp
issue description: There is a memory leak in the pool class due to a cyclic dependency between the pool and the data classes.
fix:
diff --git a/src/messages/data.hpp b/src/messages/data.hpp
--- a/src/messages/data.hpp
+++ b/src/messages/data.hpp
@@ -61,6 +61,7 @@ template
public:
typedef pool<element_type> type;
typedef boost::shared_ptr ptr;
-
typedef boost::weak_ptr<type> ptr_weak;
typedef typename element_type::ptr element_ptr;
typedef boost::function<void()> callback_type;
@@ -149,6 +150,7 @@ class data {
public:
typedef boost::intrusive_ptr ptr;
typedef pool::ptr pool_ptr;
-
typedef pool<data>::ptr_weak pool_weak_ptr;
data(pool_ptr p, size_t s);
@@ -210,7 +212,10 @@ private:
if (count == 1 && s->m_live) {
// recycle if endpoint exists
s->m_live = false;
-
s->m_pool->recycle(ptr(const_cast<data *>(s)));
-
pool_ptr pp = s->m_pool.lock();
-
if (pp != NULL) {
-
pp->recycle(ptr(const_cast<data *>(s)));
-
}
} else if (count == 0) {
boost::checked_delete(static_cast<data const *>(s));
}
@@ -235,7 +240,7 @@ private:
// reference counting
size_t m_index;
mutable boost::detail::atomic_count m_ref_count;
- mutable pool_ptr m_pool;
mutable pool_weak_ptr m_pool;
mutable bool m_live;
};
Allow multiple headers with same name
note this depends on the field type. Sec-WebSocket-Version requests must be singled valued, error responses may be multi-valued (Sec 11.3). subprotocol may be multivalued, also extensions
audit closing behavior
I have flagged exit points with TODO: close behavior. These need to be simplified and I need to make sure that all paths result in compliant close behavior.
Working with data on the stack during async_write
There is a couple of places where the async_write method is called using a local string variable as the buffer parameter. The places are
void client::connection<connection_type>::write_request() {
.....
boost::asio::async_write(
m_connection.get_socket(),
boost::asio::buffer(raw),
.....
and
void server::connection<connection_type>::write_response() {
.....
boost::asio::async_write(
m_connection.get_socket(),
boost::asio::buffer(raw),
I fixed the issue by using a reference counted buffer from an asio example. The class code is
class shared_const_buffer {
public:
explicit shared_const_buffer(const std::string &data) : m_data(new std::vector<char>(data.begin(), data.end())),
m_buffer(boost::asio::buffer(*m_data)) {}
public:
typedef boost::asio::const_buffer value_type;
typedef const boost::asio::const_buffer *const_iterator;
const boost::asio::const_buffer *begin() const { return &m_buffer; }
const boost::asio::const_buffer *end() const { return &m_buffer + 1; }
private:
boost::shared_ptr< std::vector<char> > m_data;
boost::asio::const_buffer m_buffer;
};
and replacing "boost::asio::buffer(" by "shared_const_buffer"
Plus a mistyping:
diff --git a/src/roles/server.hpp b/src/roles/server.hpp
-
throw http::exception("Recieved invalid HTTP Request",http::status_code::BAD_REQUEST);
-
throw http::exception("Received invalid HTTP Request",http::status_code::BAD_REQUEST);
A few memory leaks
There are the following memory leaks:
- class client contains a shared pointer to a client session object (m_client_session), which is instanced in the client::init method. Also the client_session class contains a shared pointer to the parent session m_client. Instancing the client class object as its shared pointer reference counter equals to 1, after calling its init method the reference counter equals to 2, due to the reference in the session object. By deleting the client object reference becomes to 1 and the client object is never deleted.
To resolve this cyclic dependency is necessary to use the boost::weak_ptr class instead of boost::shared_ptr for the client_session::m_client member.
- A similar cyclic dependency between the server and server_session classes. The server_session::m_server member type changing to boost::weak_ptr is required to fix it.
- If a server is stopped by calling of the stop method of the parent boost::asio::io_service instance and the server has connected clients, when active connections which are stored in connection_handler inherited class (the example chat_server_handler class) are not deleted. A fast but not universal solution to fix this issue is to mandatory clear the connections list (chat_server_handler::m_connections) after call of io_service.run.
a few small issues
Found a few small issues in the source code.
- method "frame::reset" should contain "m_payload.clear()" instead of "m_payload.empty()"
- method seems forgotten & in parameters of the following methods
- both of "frame::set_payload"
- frame::set_status
- Misprint in "throw frame_error("requested payload is over..." of the "frame::set_payload_helper" method. Word - implementation.
Frame based send API
Add an API to the connection handler to allow local applications to send messages in fragments as data becomes available rather than waiting until the entire message has been buffered.
Review and document all outstanding draft 17 protocol conformance issues
Ploicy-Refactor: Client Class Issue
file: client.hpp
method: client::connect(const std::string& u)
line: connection_ptr con = m_endpoint.create_connection();
issue description: the con variable can be equal to NULL if the endpoint is in either the stopping or stopped state.
fix:
connection_ptr con = m_endpoint.create_connection();
- con->set_uri(location);
-
- boost::asio::async_connect(
- con->get_raw_socket(),
- iterator,
- boost::bind(
- &endpoint_type::handle_connect,
- this, // shared from this?
- con,
- boost::asio::placeholders::error
- )
- );
- m_state = CONNECTING;
+ if (con != NULL) {
+ con->set_uri(location);
+
+ boost::asio::async_connect(
+ con->get_raw_socket(),
+ iterator,
+ boost::bind(
+ &endpoint_type::handle_connect,
+ this, // shared from this?
+ con,
+ boost::asio::placeholders::error
+ )
+ );
+ m_state = CONNECTING;
+ }
return con;
client non-101 response behavior
HTTP basic auth on 401, redirects on 3xx, etc
see section 4.1, 10.5
Switch to a streaming ASIO API from fixed length read
Prerequisite for most of the other features in this milestone
Chat client participant listing
audit security/resource usage related limits
max messages sizes (see section 10.4)
time waiting for a handshake after connecting
number of connections per endpoint (see section 4.1 part 3)
Method for cleanly quitting the server
At minimum, catch SIGINT and close all connections/write logs cleanly. Consider how this might work on non-unix systems?
Write client handshake
Recovering From Abnormal Closure
See section 7.2.3
Right now this is all up to the end application. Should any of this be supported by the library?
Web socket key generation
Allow HTTP versions greater than 1.1
Handshake acceptance code is currently hard coded to accept only HTTP/1.1
closing handshake error codes
Closing handshakes do not include error codes
Error compiling examples on Ubuntu natty and oneiric
I was using Boost 1.47 compiled from source.
Now library build without issue on both, shared and static. But is a problem compiling examples, same problem on four examples.
root@xubuntu:/DEVELOP/websocketpp/examples/chat_client# make
g++ -c -O2 -o chat_client.o chat_client.cpp
g++ -c -O2 -o chat_client_handler.o chat_client_handler.cpp
g++ -O2 chat_client.o chat_client_handler.o -o chat_client -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_random ../../libwebsocketpp.a
../../libwebsocketpp.a(websocket_session.o): In function websocketpp::session::session(boost::asio::io_service&, boost::shared_ptrwebsocketpp::connection_handler, unsigned long long)':
websocket_session.cpp:(.text+0x2345): undefined reference toboost::random::random_device::random_device()'
websocket_session.cpp:(.text+0x23a0): undefined reference to boost::random::random_device::random_device()'
websocket_session.cpp:(.text+0x24c9): undefined reference toboost::random::random_device::~random_device()'
websocket_session.cpp:(.text+0x24e5): undefined reference to boost::random::random_device::~random_device()'
websocket_session.cpp:(.text+0x25c7): undefined reference toboost::random::random_device::~random_device()'
.
.
.
Thanks!
Error compiling on Ubuntu natty and oneiric
Hello!!
Trying to compile on natty and oneiric. gcc -4.5.2 and gcc-4.6.1
.
.
src/websocket_frame.hpp: In constructor ‘websocketpp::frame::frame()’:
src/websocket_frame.hpp:99:54: error: ‘INT32_MIN’ was not declared in this scope
src/websocket_frame.hpp:99:64: error: ‘INT32_MAX’ was not declared in this scope
.
Frame based receive API
Add an API to the connection handler to allow local applications to receive fragmented messages in fragments as they arrive rather than waiting until the entire message has been buffered.
Reject masked frames from client
per section 5.1
WebSocket URL parsing
switch to using 4 spaces instead of tabs
like the project, my other code style guide requires 4 spaces so kinda clashy, just a request! :)
Thanks for your hard work.
Streaming receive API
Add an API to the connection handler to allow local applications to receive message data as it arrives rather than waiting until the entire fragment has been buffered.
Behavior of send while another send is in progress
This needs to be defined and enforced. Either send should queue (if this is the case the queue should be short) or send should fail. With a fixed size queue send will fail at some point anyways.
utf8 validation
utf8 validation is not being done.
client should wait for server to close TCP
see section 7.1.1
A few issues in the policy-refactor
All issues bellow are in the endpoint.hpp file.
- The endpoint::close_all method iterates the m_connections set and calls the close method of every element. the result is a crash, because the close method calls the endpoint::remove_connection method which removes the connection from the m_connections member. Quick but not "nice" fix is
-
for (it = m_connections.begin(); it != m_connections.end(); it++) {
-
(*it)->close(code,reason);
-
}
-
while(!m_connections.empty()) { // using for is not correct because the close method calls the remove_connection, which removes connection from m_connections
-
(*m_connections.begin())->close(code,reason);
-
}
-
Ambiguous access of 'm_io_service'. Can be either the endpoint_base or the role or the socket classes. Fix is
explicit endpoint(handler_ptr handler)
-
: role_type(m_io_service),
-
socket_type(m_io_service),
-
: role_type(endpoint_base::m_io_service),
-
socket_type(endpoint_base::m_io_service),
m_state(IDLE),
-
The same as previous issue but in different place
<< "Endpoint is stopping immediately" << log::endl;
-
m_io_service.stop();
-
endpoint_base::m_io_service.stop();
m_state = STOPPED;
-
Under Windows the following lines either can't be compiled or do not define correct friend class declarations and as result the "can't access to protected method" error
friend class role< endpoint<role,socket> >;
friend class socket< endpoint<role,socket> >;
friend class connection<type,role< type >::template connection,socket< type >::template connection>;
Quick but not 100% correct fix is to use #if defined(WIN32) ... #else ... #endif with the following lines which are commented in the header file
friend role_type;
friend socket_type;
friend connection_type;
- Simple mistyping.
-
<< "Endpoint recieved signal to close all connections cleanly with code "
-
<< "Endpoint received signal to close all connections cleanly with code "
Implementation defined message size limits are not enforced
limit total number of "connecting" connections
per section 4.1 part 2
Policy Refactor: Correct fix of the issue's #50 endpoint::close_all problem
In the issue #50 the 1st problem was linked with the endpoint::close_all method. And the fix is not correct due to the fact that the remove_connection method is not called on every close method and result is a never-ending loop. Here is a new fix:
- while(!m_connections.empty()) {
-
(*m_connections.begin())->close(code,reason);
-
}
-
for (std::set<connection_ptr>::iterator it_con = m_connections.begin(); it_con != m_connections.end();) {
-
const connection_ptr con = *it_con++;
-
con->close(code,reason);
}
The logic is that initially the existent iterator is incremented and after may be called the m_connections.erase() method. Before the issue #50 the for circle incremented the iterator after the m_connections.erase() call.
Small issues to make compilable the policy-refactor branch under Windows
diff --git a/src/rng/boost_rng.cpp b/src/rng/boost_rng.cpp
- boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)); {}
- boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)) {}
diff --git a/src/processors/hybi_header.cpp b/src/processors/hybi_header.cpp
-void hybi_header::set_opcode(frame::opcode::value op) {
+void hybi_header::set_opcode(websocketpp::frame::opcode::value op) {
diff --git a/src/processors/hybi_header.hpp b/src/processors/hybi_header.hpp
- void set_opcode(frame::opcode::value op);
- void set_opcode(websocketpp::frame::opcode::value op);
diff --git a/src/messages/data.cpp b/src/messages/data.cpp
-
m_payload.reserve(std::max(new_size,static_cast<uint64_t>(2*m_payload.capacity())));
-
m_payload.reserve(std::max<uint64_t>(new_size, static_cast<uint64_t>(2*m_payload.capacity())));
-void data::reset(frame::opcode::value opcode) {
+void data::reset(websocketpp::frame::opcode::value opcode) {
diff --git a/src/messages/data.hpp b/src/messages/data.hpp
- void reset(frame::opcode::value opcode);
- void reset(websocketpp::frame::opcode::value opcode);
ideal set_max_message_size error behavior?
Options:
- Throw exception
- Log error and set value to maximum allowed
- Log error and leave value at whatever it was before
examples/chat_server bug
When client disconnects, chat server doesn't remove session_ptr
from m_connections
(chat.cpp, line #79):
send_to_all(encode_message("server",m_connections[client]+" has left the chat."));
this makes server crazy, after sending messages from other clients.
The following logic should fix this:
std::cout << "client " << client << " left the lobby." << std::endl;
const std::string alias = it->second;
m_connections.erase(it);
// send user list and signoff message to all clients
send_to_all(serialize_state());
send_to_all(encode_message("server", alias+" has left the chat."));
url parsing shouldn't allow fragments (#) per section 3
Client Handshake validation
Recommend Projects
-
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
-
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
-