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
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;
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."));
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?
see section 7.1.1
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.
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.
Prerequisite for most of the other features in this milestone
There are the following memory leaks:
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.
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})?(/[^#]*)?");
Chat server example doesn't work with the new API
per section 5.1
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
.
per section 4.1 part 2
Closing handshakes do not include error codes
like the project, my other code style guide requires 4 spaces so kinda clashy, just a request! :)
Thanks for your hard work.
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;
};
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);
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
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?
Write client handshake
Review and document all outstanding draft 17 protocol conformance issues
utf8 validation
utf8 validation is not being done.
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);
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!
Client Handshake validation
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 "
unsupported version behavior
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.
Frames read in with handshake are lost
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.
Basic chat client example
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.
Allow HTTP versions greater than 1.1
Handshake acceptance code is currently hard coded to accept only HTTP/1.1
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?
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
client non-101 response behavior
HTTP basic auth on 401, redirects on 3xx, etc
see section 4.1, 10.5
TLS Support
is required by the spec
see section 10.6
url parsing shouldn't allow fragments (#) per section 3
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.
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.
WebSocket URL parsing
Masking key generation
message length encoding validation
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
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.
Sec-Websocket-Origin
has changed to Origin in protocol 13
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.
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.
-