Use websocketpp_02 namespace.

This commit is contained in:
Tom Ritchford
2015-01-20 17:08:15 -05:00
parent dbc1d70f99
commit bcf4f836b4
37 changed files with 1683 additions and 1683 deletions

View File

@@ -44,7 +44,7 @@ public:
static char const* getCountedObjectName () { return "WSConnection"; }
protected:
typedef websocketpp::message::data::ptr message_ptr;
typedef websocketpp_02::message::data::ptr message_ptr;
WSConnection (HTTP::Port const& port,
Resource::Manager& resourceManager, Resource::Consumer usage,
@@ -174,7 +174,7 @@ public:
connection_ptr ptr = c.lock ();
if (ptr)
ptr->close (websocketpp::close::status::PROTOCOL_ERROR, "overload");
ptr->close (websocketpp_02::close::status::PROTOCOL_ERROR, "overload");
}
bool onPingTimer (std::string&)

View File

@@ -56,7 +56,7 @@ private:
Resource::Manager& m_resourceManager;
InfoSub::Source& m_source;
LockType m_endpointLock;
std::shared_ptr<websocketpp::server_autotls> m_endpoint;
std::shared_ptr<websocketpp_02::server_autotls> m_endpoint;
public:
WSDoorImp (HTTP::Port const& port, Resource::Manager& resourceManager,
@@ -83,14 +83,14 @@ private:
port_->ip.to_string() << ":" << std::to_string(port_->port) <<
(port_->allow_admin ? "(Admin)" : "");
websocketpp::server_autotls::handler::ptr handler (
new WSServerHandler <websocketpp::server_autotls> (
websocketpp_02::server_autotls::handler::ptr handler (
new WSServerHandler <websocketpp_02::server_autotls> (
port_, m_resourceManager, m_source));
{
ScopedLockType lock (m_endpointLock);
m_endpoint = std::make_shared<websocketpp::server_autotls> (
m_endpoint = std::make_shared<websocketpp_02::server_autotls> (
handler);
}
@@ -99,24 +99,24 @@ private:
{
m_endpoint->listen (port_->ip, port_->port);
}
catch (websocketpp::exception& e)
catch (websocketpp_02::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: "
WriteLog (lsWARNING, WSDoor) << "websocketpp_02 exception: "
<< e.what ();
// temporary workaround for websocketpp throwing exceptions on
// temporary workaround for websocketpp_02 throwing exceptions on
// access/close races
for (;;)
{
// https://github.com/zaphoyd/websocketpp/issues/98
// https://github.com/zaphoyd/websocketpp_02/issues/98
try
{
m_endpoint->get_io_service ().run ();
break;
}
catch (websocketpp::exception& e)
catch (websocketpp_02::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: "
WriteLog (lsWARNING, WSDoor) << "websocketpp_02 exception: "
<< e.what ();
}
}
@@ -133,7 +133,7 @@ private:
void onStop ()
{
std::shared_ptr<websocketpp::server_autotls> endpoint;
std::shared_ptr<websocketpp_02::server_autotls> endpoint;
{
ScopedLockType lock (m_endpointLock);

View File

@@ -111,7 +111,7 @@ public:
}
catch (...)
{
cpClient->close (websocketpp::close::status::value (crTooSlow),
cpClient->close (websocketpp_02::close::status::value (crTooSlow),
std::string ("Client is too slow."));
}
}
@@ -128,7 +128,7 @@ public:
}
catch (...)
{
cpClient->close (websocketpp::close::status::value (crTooSlow),
cpClient->close (websocketpp_02::close::status::value (crTooSlow),
std::string ("Client is too slow."));
}
}
@@ -397,7 +397,7 @@ public:
{
}
if (mpMessage->get_opcode () != websocketpp::frame::opcode::TEXT)
if (mpMessage->get_opcode () != websocketpp_02::frame::opcode::TEXT)
{
Json::Value jvResult (Json::objectValue);

View File

@@ -22,14 +22,14 @@
// VFALCO NOTE this looks like some facility for giving websocket
// a way to produce logging output.
//
namespace websocketpp {
namespace websocketpp_02 {
namespace log {
void websocketLog (websocketpp::log::alevel::value v, std::string const& entry)
void websocketLog (websocketpp_02::log::alevel::value v, std::string const& entry)
{
using namespace ripple;
if ((v == websocketpp::log::alevel::DEVEL) || (v == websocketpp::log::alevel::DEBUG_CLOSE))
if ((v == websocketpp_02::log::alevel::DEVEL) || (v == websocketpp_02::log::alevel::DEBUG_CLOSE))
{
WriteLog(lsTRACE, WebSocket) << entry;
}
@@ -39,19 +39,19 @@ void websocketLog (websocketpp::log::alevel::value v, std::string const& entry)
}
}
void websocketLog (websocketpp::log::elevel::value v, std::string const& entry)
void websocketLog (websocketpp_02::log::elevel::value v, std::string const& entry)
{
using namespace ripple;
LogSeverity s = lsDEBUG;
if ((v & websocketpp::log::elevel::INFO) != 0)
if ((v & websocketpp_02::log::elevel::INFO) != 0)
s = lsINFO;
else if ((v & websocketpp::log::elevel::FATAL) != 0)
else if ((v & websocketpp_02::log::elevel::FATAL) != 0)
s = lsFATAL;
else if ((v & websocketpp::log::elevel::RERROR) != 0)
else if ((v & websocketpp_02::log::elevel::RERROR) != 0)
s = lsERROR;
else if ((v & websocketpp::log::elevel::WARN) != 0)
else if ((v & websocketpp_02::log::elevel::WARN) != 0)
s = lsWARNING;
WriteLog(s, WebSocket) << entry;

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_CONSTANTS_HPP
@@ -52,29 +52,29 @@
#include <boost/shared_ptr.hpp>
// Defaults
namespace websocketpp {
namespace websocketpp_02 {
static const std::string USER_AGENT = "WebSocket++/0.2.1dev";
typedef std::vector<unsigned char> binary_string;
typedef boost::shared_ptr<binary_string> binary_string_ptr;
typedef std::string utf8_string;
typedef boost::shared_ptr<utf8_string> utf8_string_ptr;
const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB
const size_t DEFAULT_READ_THRESHOLD = 1; // 512 would be a more sane value for this
const bool DEFAULT_SILENT_CLOSE = false; // true
const size_t MAX_THREAD_POOL_SIZE = 64;
const uint16_t DEFAULT_PORT = 80;
const uint16_t DEFAULT_SECURE_PORT = 443;
inline uint16_t default_port(bool secure) {
return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
}
}
namespace session {
namespace state {
enum value {
@@ -85,7 +85,7 @@ namespace websocketpp {
};
}
}
namespace close {
namespace status {
enum value {
@@ -110,24 +110,24 @@ namespace websocketpp {
RSV_END = 2999,
INVALID_START = 5000
};
inline bool reserved(value s) {
return ((s >= RSV_START && s <= RSV_END) || s == RSV_ADHOC_1
return ((s >= RSV_START && s <= RSV_END) || s == RSV_ADHOC_1
|| s == RSV_ADHOC_2 || s == RSV_ADHOC_3 || s == RSV_ADHOC_4);
}
// Codes invalid on the wire
inline bool invalid(value s) {
return ((s <= INVALID_END || s >= INVALID_START) ||
s == NO_STATUS ||
s == ABNORMAL_CLOSE ||
return ((s <= INVALID_END || s >= INVALID_START) ||
s == NO_STATUS ||
s == ABNORMAL_CLOSE ||
s == TLS_HANDSHAKE);
}
// TODO functions for application ranges?
} // namespace status
} // namespace close
namespace fail {
namespace status {
enum value {
@@ -140,7 +140,7 @@ namespace websocketpp {
};
} // namespace status
} // namespace fail
namespace frame {
// Opcodes are 4 bits
// See spec section 5.2
@@ -163,28 +163,28 @@ namespace websocketpp {
CONTROL_RSVE = 0xE,
CONTROL_RSVF = 0xF
};
inline bool reserved(value v) {
return (v >= RSV3 && v <= RSV7) ||
return (v >= RSV3 && v <= RSV7) ||
(v >= CONTROL_RSVB && v <= CONTROL_RSVF);
}
inline bool invalid(value v) {
return (v > 0xF || v < 0);
}
inline bool is_control(value v) {
return v >= 0x8;
}
}
namespace limits {
static const uint8_t PAYLOAD_SIZE_BASIC = 125;
static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFFLL;//2^63
}
} // namespace frame
// exception class for errors that should be propogated back to the user.
namespace error {
enum value {
@@ -199,22 +199,22 @@ namespace websocketpp {
INVALID_STATE = 7
};
}
class exception : public std::exception {
public:
public:
exception(const std::string& msg,
error::value code = error::GENERIC)
error::value code = error::GENERIC)
: m_msg(msg),m_code(code) {}
~exception() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
error::value code() const throw() {
return m_code;
}
std::string m_msg;
error::value m_code;
};

File diff suppressed because it is too large Load Diff

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_ENDPOINT_HPP
@@ -40,8 +40,8 @@
#include <iostream>
#include <set>
namespace websocketpp {
namespace websocketpp_02 {
/// endpoint_base provides core functionality that needs to be constructed
/// before endpoint policy classes are constructed.
class endpoint_base {
@@ -57,17 +57,17 @@ protected:
}
}
}
boost::asio::io_service m_io_service;
};
/// Describes a configurable WebSocket endpoint.
/**
* The endpoint class template provides a configurable WebSocket endpoint
* capable that manages WebSocket connection lifecycles. endpoint is a host
* The endpoint class template provides a configurable WebSocket endpoint
* capable that manages WebSocket connection lifecycles. endpoint is a host
* class to a series of enriched policy classes that together provide the public
* interface for a specific type of WebSocket endpoint.
*
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Will be safe when complete.
@@ -76,7 +76,7 @@ template <
template <class> class role,
template <class> class socket = socket::autotls,
template <class> class logger = log::logger>
class endpoint
class endpoint
: public endpoint_base,
public role< endpoint<role,socket,logger> >,
public socket< endpoint<role,socket,logger> >
@@ -84,7 +84,7 @@ class endpoint
public:
/// Type of the traits class that stores endpoint related types.
typedef endpoint_traits< endpoint<role,socket,logger> > traits;
/// The type of the endpoint itself.
typedef typename traits::type type;
/// The type of a shared pointer to the endpoint.
@@ -109,10 +109,10 @@ public:
/// A shared pointer to the base class that all handlers for this endpoint
/// must derive from.
typedef typename traits::handler_ptr handler_ptr;
// Friend is used here to allow the CRTP base classes to access member
// functions in the derived endpoint. This is done to limit the use of
// public methods in endpoint and its CRTP bases to only those methods
// Friend is used here to allow the CRTP base classes to access member
// functions in the derived endpoint. This is done to limit the use of
// public methods in endpoint and its CRTP bases to only those methods
// intended for end-application use.
#ifdef _WEBSOCKETPP_CPP11_FRIEND_
// Highly simplified and preferred C++11 version:
@@ -124,17 +124,17 @@ public:
friend class socket< endpoint<role,socket> >;
friend class connection<type,role< type >::template connection,socket< type >::template connection>;
#endif
/// Construct an endpoint.
/**
* This constructor creates an endpoint and registers the default connection
* handler.
*
*
* @param handler A shared_ptr to the handler to use as the default handler
* when creating new connections.
*/
explicit endpoint(handler_ptr handler)
explicit endpoint(handler_ptr handler)
: role_type(endpoint_base::m_io_service)
, socket_type(endpoint_base::m_io_service)
, m_handler(handler)
@@ -148,36 +148,36 @@ public:
{
m_pool->set_callback(boost::bind(&type::on_new_message,this));
}
/// Destroy an endpoint
~endpoint() {
m_alog->at(log::alevel::DEVEL) << "Endpoint destructor called" << log::endl;
// Tell the memory pool we don't want to be notified about newly freed
// messages any more (because we wont be here)
m_pool->set_callback(NULL);
// Detach any connections that are still alive at this point
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
typename std::set<connection_ptr>::iterator it;
while (!m_connections.empty()) {
remove_connection(*m_connections.begin());
}
m_alog->at(log::alevel::DEVEL) << "Endpoint destructor done" << log::endl;
}
// copy/assignment constructors require C++11
// boost::noncopyable is being used in the meantime.
// endpoint(endpoint const&) = delete;
// endpoint& operator=(endpoint const&) = delete
/// Returns a reference to the endpoint's access logger.
/**
* Visibility: public
* State: Any
* Concurrency: Callable from anywhere
*
*
* @return A reference to the endpoint's access logger. See @ref logger
* for more details about WebSocket++ logging policy classes.
*
@@ -193,7 +193,7 @@ public:
alogger_ptr alog_ptr() {
return m_alog;
}
/// Returns a reference to the endpoint's error logger.
/**
* @returns A reference to the endpoint's error logger. See @ref logger
@@ -211,162 +211,162 @@ public:
elogger_ptr elog_ptr() {
return m_elog;
}
/// Get default handler
/**
* Visibility: public
* State: valid always
* Concurrency: callable from anywhere
*
*
* @return A pointer to the default handler
*/
handler_ptr get_handler() const {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
return m_handler;
}
/// Sets the default handler to be used for future connections
/**
* Does not affect existing connections.
*
*
* @param new_handler A shared pointer to the new default handler. Must not
* be NULL.
*/
void set_handler(handler_ptr new_handler) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
if (!new_handler) {
elog().at(log::elevel::FATAL)
elog().at(log::elevel::FATAL)
<< "Tried to switch to a NULL handler." << log::endl;
throw websocketpp::exception("TODO: handlers can't be null");
throw websocketpp_02::exception("TODO: handlers can't be null");
}
m_handler = new_handler;
}
/// Set endpoint read threshold
/**
* Sets the default read threshold value that will be passed to new connections.
* Sets the default read threshold value that will be passed to new connections.
* Changing this value will only affect new connections, not existing ones. The read
* threshold represents the largest block of payload bytes that will be processed in
* a single async read. Lower values may experience better callback latency at the
* a single async read. Lower values may experience better callback latency at the
* expense of additional ASIO context switching overhead. This value also affects the
* maximum number of bytes to be buffered before performing utf8 and other streaming
* validation.
*
*
* Visibility: public
* State: valid always
* Concurrency: callable from anywhere
*
*
* @param val Size of the threshold in bytes
*/
void set_read_threshold(size_t val) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
m_read_threshold = val;
}
/// Get endpoint read threshold
/**
* Returns the endpoint read threshold. See set_read_threshold for more information
* about the read threshold.
*
*
* Visibility: public
* State: valid always
* Concurrency: callable from anywhere
*
*
* @return Size of the threshold in bytes
* @see set_read_threshold()
*/
size_t get_read_threshold() const {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
return m_read_threshold;
}
/// Set connection silent close setting
/**
* Silent close suppresses the return of detailed connection close information during
* the closing handshake. This information is critically useful for debugging but may
* be undesirable for security reasons for some production environments. Close reasons
* could be used to by an attacker to confirm that the implementation is out of
* could be used to by an attacker to confirm that the implementation is out of
* resources or be used to identify the WebSocket library in use.
*
*
* Visibility: public
* State: valid always
* Concurrency: callable from anywhere
*
*
* @param val New silent close value
*/
void set_silent_close(bool val) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
m_silent_close = val;
}
/// Get connection silent close setting
/**
* Visibility: public
* State: valid always
* Concurrency: callable from anywhere
*
*
* @return Current silent close value
* @see set_silent_close()
*/
bool get_silent_close() const {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
return m_silent_close;
}
/// Cleanly closes all websocket connections
/**
* Sends a close signal to every connection with the specified code and
* Sends a close signal to every connection with the specified code and
* reason. The default code is 1001/Going Away and the default reason is
* blank.
*
* blank.
*
* @param code The WebSocket close code to send to remote clients as the
* reason that the connection is being closed.
* @param reason The WebSocket close reason to send to remote clients as the
* text reason that the connection is being closed. Must be valid UTF-8.
*/
void close_all(close::status::value code = close::status::GOING_AWAY,
void close_all(close::status::value code = close::status::GOING_AWAY,
const std::string& reason = "")
{
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint received signal to close all connections cleanly with code "
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint received signal to close all connections cleanly with code "
<< code << " and reason " << reason << log::endl;
// TODO: is there a more elegant way to do this? In some code paths
// TODO: is there a more elegant way to do this? In some code paths
// close can call terminate immediately which removes the connection
// from m_connections, invalidating the iterator.
typename std::set<connection_ptr>::iterator it;
for (it = m_connections.begin(); it != m_connections.end();) {
const connection_ptr con = *it++;
con->close(code,reason);
}
}
/// Stop the endpoint's ASIO loop
/**
* Signals the endpoint to call the io_service stop member function. If
* Signals the endpoint to call the io_service stop member function. If
* clean is true the endpoint will be put into an intermediate state where
* it signals all connections to close cleanly and only calls stop once that
* process is complete. Otherwise stop is called immediately and all
* process is complete. Otherwise stop is called immediately and all
* io_service operations will be aborted.
*
* If clean is true stop will use code and reason for the close code and
* close reason when it closes open connections. The default code is
*
* If clean is true stop will use code and reason for the close code and
* close reason when it closes open connections. The default code is
* 1001/Going Away and the default reason is blank.
*
*
* Visibility: public
* State: Valid from RUNNING only
* Concurrency: Callable from anywhere
*
*
* @param clean Whether or not to wait until all connections have been
* cleanly closed to stop io_service operations.
* @param code The WebSocket close code to send to remote clients as the
@@ -374,22 +374,22 @@ public:
* @param reason The WebSocket close reason to send to remote clients as the
* text reason that the connection is being closed. Must be valid UTF-8.
*/
void stop(bool clean = true,
close::status::value code = close::status::GOING_AWAY,
void stop(bool clean = true,
close::status::value code = close::status::GOING_AWAY,
const std::string& reason = "")
{
{
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
if (clean) {
m_alog->at(log::alevel::ENDPOINT)
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint is stopping cleanly" << log::endl;
m_state = STOPPING;
close_all(code,reason);
} else {
m_alog->at(log::alevel::ENDPOINT)
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint is stopping immediately" << log::endl;
endpoint_base::m_io_service.stop();
m_state = STOPPED;
}
@@ -397,15 +397,15 @@ public:
protected:
/// Creates and returns a new connection
/**
* This function creates a new connection of the type and passes it a
* This function creates a new connection of the type and passes it a
* reference to this as well as a shared pointer to the default connection
* handler. The newly created connection is added to the endpoint's
* management list. The endpoint will retain this pointer until
* handler. The newly created connection is added to the endpoint's
* management list. The endpoint will retain this pointer until
* remove_connection is called to remove it.
*
* If the endpoint is in a state where it is trying to stop or has already
* stopped an empty shared pointer is returned.
*
*
* Visibility: protected
* State: Always valid, behavior differs based on state
* Concurrency: Callable from anywhere
@@ -415,93 +415,93 @@ protected:
*/
connection_ptr create_connection() {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
if (m_state == STOPPING || m_state == STOPPED) {
return connection_ptr();
}
connection_ptr new_connection(new connection_type(*this,m_handler));
m_connections.insert(new_connection);
m_alog->at(log::alevel::DEVEL) << "Connection created: count is now: "
m_alog->at(log::alevel::DEVEL) << "Connection created: count is now: "
<< m_connections.size() << log::endl;
return new_connection;
}
/// Removes a connection from the list managed by this endpoint.
/**
* This function erases a connection from the list managed by the endpoint.
* After this function returns, endpoint all async events related to this
* connection should be canceled and neither ASIO nor this endpoint should
* have a pointer to this connection. Unless the end user retains a copy of
* the shared pointer the connection will be freed and any state it
* the shared pointer the connection will be freed and any state it
* contained (close code status, etc) will be lost.
*
*
* Visibility: protected
* State: Always valid, behavior differs based on state
* Concurrency: Callable from anywhere
*
*
* @param con A shared pointer to a connection created by this endpoint.
*/
void remove_connection(connection_ptr con) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
// TODO: is this safe to use?
// Detaching signals to the connection that the endpoint is no longer aware of it
// and it is no longer safe to assume the endpoint exists.
con->detach();
m_connections.erase(con);
m_alog->at(log::alevel::DEVEL) << "Connection removed: count is now: "
m_alog->at(log::alevel::DEVEL) << "Connection removed: count is now: "
<< m_connections.size() << log::endl;
if (m_state == STOPPING && m_connections.empty()) {
// If we are in the process of stopping and have reached zero
// connections stop the io_service.
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
m_alog->at(log::alevel::ENDPOINT)
<< "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
<< log::endl;
stop(false);
}
}
/// Gets a shared pointer to a read/write data message.
// TODO: thread safety
message::data::ptr get_data_message() {
return m_pool->get();
}
/// Gets a shared pointer to a read/write control message.
// TODO: thread safety
message::data::ptr get_control_message() {
return m_pool_control->get();
}
/// Asks the endpoint to restart this connection's handle_read_frame loop
/// when there are avaliable data messages.
void wait(connection_ptr con) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
m_read_waiting.push(con);
m_alog->at(log::alevel::DEVEL) << "connection " << con << " is waiting. " << m_read_waiting.size() << log::endl;
}
/// Message pool callback indicating that there is a free data message
/// avaliable. Causes one waiting connection to get restarted.
void on_new_message() {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
if (!m_read_waiting.empty()) {
connection_ptr next = m_read_waiting.front();
m_alog->at(log::alevel::DEVEL) << "Waking connection " << next << ". " << m_read_waiting.size()-1 << log::endl;
(*next).handle_read_frame(boost::system::error_code());
m_read_waiting.pop();
}
}
private:
@@ -511,29 +511,29 @@ private:
STOPPING = 2,
STOPPED = 3
};
// default settings to pass to connections
handler_ptr m_handler;
size_t m_read_threshold;
bool m_silent_close;
// other stuff
state m_state;
std::set<connection_ptr> m_connections;
alogger_ptr m_alog;
elogger_ptr m_elog;
// resource pools for read/write message buffers
message::pool<message::data>::ptr m_pool;
message::pool<message::data>::ptr m_pool_control;
std::queue<connection_ptr> m_read_waiting;
// concurrency support
mutable boost::recursive_mutex m_lock;
};
/// traits class that allows looking up relevant endpoint types by the fully
/// traits class that allows looking up relevant endpoint types by the fully
/// defined endpoint type.
template <
template <class> class role,
@@ -543,32 +543,32 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
/// The type of the endpoint itself.
typedef endpoint<role,socket,logger> type;
typedef boost::shared_ptr<type> ptr;
/// The type of the role policy.
typedef role< type > role_type;
/// The type of the socket policy.
typedef socket< type > socket_type;
/// The type of the access logger based on the logger policy.
typedef logger<log::alevel::value> alogger_type;
typedef boost::shared_ptr<alogger_type> alogger_ptr;
/// The type of the error logger based on the logger policy.
typedef logger<log::elevel::value> elogger_type;
typedef boost::shared_ptr<elogger_type> elogger_ptr;
/// The type of the connection that this endpoint creates.
typedef connection<type,
role< type >::template connection,
socket< type >::template connection> connection_type;
/// A shared pointer to the type of connection that this endpoint creates.
typedef boost::shared_ptr<connection_type> connection_ptr;
class handler;
/// A shared pointer to the base class that all handlers for this endpoint
/// must derive from.
typedef boost::shared_ptr<handler> handler_ptr;
/// Interface (ABC) that handlers for this type of endpoint may impliment.
/// role policy and socket policy both may add methods to this interface
class handler : public role_type::handler_interface,
@@ -580,9 +580,9 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
typedef boost::shared_ptr<handler> ptr;
typedef typename connection_type::ptr connection_ptr;
typedef typename message::data::ptr message_ptr;
virtual ~handler() {}
/// on_load is the first callback called for a handler after a new
/// connection has been transferred to it mid flight.
/**
@@ -598,9 +598,9 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
*/
virtual void on_unload(connection_ptr con, handler_ptr new_handler) {}
};
};
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKETPP_ENDPOINT_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,19 +22,19 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef HTTP_CONSTANTS_HPP
#define HTTP_CONSTANTS_HPP
namespace websocketpp {
namespace websocketpp_02 {
namespace http {
namespace status_code {
enum value {
CONTINUE = 100,
SWITCHING_PROTOCOLS = 101,
OK = 200,
CREATED = 201,
ACCEPTED = 202,
@@ -42,7 +42,7 @@ namespace http {
NO_CONTENT = 204,
RESET_CONTENT = 205,
PARTIAL_CONTENT = 206,
MULTIPLE_CHOICES = 300,
MOVED_PERMANENTLY = 301,
FOUND = 302,
@@ -50,7 +50,7 @@ namespace http {
NOT_MODIFIED = 304,
USE_PROXY = 305,
TEMPORARY_REDIRECT = 307,
BAD_REQUEST = 400,
UNAUTHORIZED = 401,
PAYMENT_REQUIRED = 402,
@@ -74,7 +74,7 @@ namespace http {
PRECONDITION_REQUIRED = 428,
TOO_MANY_REQUESTS = 429,
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
INTERNAL_SERVER_ERROR = 500,
NOT_IMPLIMENTED = 501,
BAD_GATEWAY = 502,
@@ -84,7 +84,7 @@ namespace http {
NOT_EXTENDED = 510,
NETWORK_AUTHENTICATION_REQUIRED = 511
};
// TODO: should this be inline?
inline std::string get_string(value c) {
switch (c) {
@@ -185,9 +185,9 @@ namespace http {
}
}
}
class exception : public std::exception {
public:
public:
exception(const std::string& log_msg,
status_code::value error_code,
const std::string& error_msg = "",
@@ -197,11 +197,11 @@ namespace http {
m_error_msg(error_msg),
m_body(body) {}
~exception() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
std::string m_msg;
status_code::value m_error_code;
std::string m_error_msg;

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef HTTP_PARSER_HPP
@@ -35,7 +35,7 @@
#include "constants.hpp"
namespace websocketpp {
namespace websocketpp_02 {
namespace http {
namespace parser {
@@ -72,16 +72,16 @@ public:
bool consume (std::istream&) {
throw "Not Implemented";
}
void set_version(const std::string& version) {
// TODO: validation?
m_version = version;
}
const std::string& version() const {
return m_version;
}
std::string header(const std::string& key) const {
header_list::const_iterator h = m_headers.find(key);
if (h != m_headers.end()) {
@@ -89,14 +89,14 @@ public:
}
h = m_headers.find(tolower(key));
if (h == m_headers.end()) {
return "";
} else {
return h->second;
}
}
// multiple calls to add header will result in values aggregating.
// use replace_header if you do not want this behavior.
void add_header(const std::string &key, const std::string &val) {
@@ -107,11 +107,11 @@ public:
m_headers[key] += ", " + val;
}
}
void replace_header(const std::string &key, const std::string &val) {
m_headers[key] = val;
}
void remove_header(const std::string &key) {
m_headers.erase(key);
}
@@ -119,7 +119,7 @@ protected:
bool parse_headers(std::istream& s) {
std::string header;
std::string::size_type end;
// get headers
while (std::getline(s, header) && header != "\r") {
if (header[header.size()-1] != '\r') {
@@ -127,92 +127,92 @@ protected:
} else {
header.erase(header.end()-1);
}
end = header.find(": ",0);
if (end != std::string::npos) {
if (end != std::string::npos) {
add_header(header.substr(0,end),header.substr(end+2));
}
}
return true;
}
std::string raw_headers() {
std::stringstream raw;
header_list::iterator it;
for (it = m_headers.begin(); it != m_headers.end(); it++) {
raw << it->first << ": " << it->second << "\r\n";
}
return raw.str();
}
private:
std::string m_version;
header_list m_headers;
};
class request : public parser {
public:
public:
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
bool parse_complete(std::istream& s) {
std::string request;
// get status line
std::getline(s, request);
if (request[request.size()-1] == '\r') {
request.erase(request.end()-1);
std::stringstream ss(request);
std::string val;
ss >> val;
set_method(val);
ss >> val;
set_uri(val);
ss >> val;
set_version(val);
} else {
set_method(request);
return false;
}
return parse_headers(s);
}
// TODO: validation. Make sure all required fields have been set?
std::string raw() {
std::stringstream raw;
raw << m_method << " " << m_uri << " " << version() << "\r\n";
raw << raw_headers() << "\r\n";
return raw.str();
}
void set_method(const std::string& method) {
// TODO: validation?
m_method = method;
}
const std::string& method() const {
return m_method;
}
void set_uri(const std::string& uri) {
// TODO: validation?
m_uri = uri;
}
const std::string& uri() const {
return m_uri;
}
private:
std::string m_method;
std::string m_uri;
@@ -223,72 +223,72 @@ public:
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
bool parse_complete(std::istream& s) {
std::string response;
// get status line
std::getline(s, response);
if (response[response.size()-1] == '\r') {
response.erase(response.end()-1);
std::stringstream ss(response);
std::string str_val;
int int_val;
char char_val[256];
ss >> str_val;
set_version(str_val);
ss >> int_val;
ss.getline(char_val,256);
set_status(status_code::value(int_val),std::string(char_val));
} else {
return false;
}
return parse_headers(s);
}
// TODO: validation. Make sure all required fields have been set?
std::string raw() {
std::stringstream raw;
raw << version() << " " << m_status_code << " " << m_status_msg << "\r\n";
raw << raw_headers() << "\r\n";
raw << m_body;
return raw.str();
}
void set_status(status_code::value code) {
// TODO: validation?
m_status_code = code;
m_status_msg = get_string(code);
}
void set_status(status_code::value code, const std::string& msg) {
// TODO: validation?
m_status_code = code;
m_status_msg = msg;
}
void set_body(const std::string& value) {
if (value.size() == 0) {
remove_header("Content-Length");
m_body = "";
return;
}
std::stringstream foo;
foo << value.size();
replace_header("Content-Length", foo.str());
m_body = value;
}
status_code::value get_status_code() const {
return m_status_code;
}
const std::string& get_status_msg() const {
return m_status_msg;
}

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef ZS_LOGGER_HPP
@@ -33,15 +33,15 @@
#include <boost/date_time/posix_time/posix_time.hpp>
namespace websocketpp {
namespace websocketpp_02 {
namespace log {
namespace alevel {
typedef uint16_t value;
static const value OFF = 0x0;
// A single line on connect with connecting ip, websocket version,
// A single line on connect with connecting ip, websocket version,
// request resource, user agent, and the response code.
static const value CONNECT = 0x1;
// A single line on disconnect with wasClean status and local and remote
@@ -58,36 +58,36 @@ namespace alevel {
static const value MESSAGE_HEADER = 0x40;
// Adds payloads to message logs. Note these can be long!
static const value MESSAGE_PAYLOAD = 0x80;
// Notices about internal endpoint operations
static const value ENDPOINT = 0x100;
// DEBUG values
static const value DEBUG_HANDSHAKE = 0x8000;
static const value DEBUG_CLOSE = 0x4000;
static const value DEVEL = 0x2000;
static const value ALL = 0xFFFF;
}
namespace elevel {
typedef uint32_t value; // make these two values different types DJS
static const value OFF = 0x0;
static const value DEVEL = 0x1; // debugging
static const value LIBRARY = 0x2; // library usage exceptions
static const value INFO = 0x4; //
static const value INFO = 0x4; //
static const value WARN = 0x8; //
static const value RERROR = 0x10; // recoverable error
static const value FATAL = 0x20; // unrecoverable error
static const value ALL = 0xFFFF;
}
extern void websocketLog(alevel::value, const std::string&);
extern void websocketLog(elevel::value, const std::string&);
template <typename level_type>
class logger {
public:
@@ -96,32 +96,32 @@ public:
m_oss << a; // For now, make this unconditional DJS
return *this;
}
logger<level_type>& operator<<(logger<level_type>& (*f)(logger<level_type>&)) {
return f(*this);
}
bool test_level(level_type l) {
return (m_level & l) != 0;
}
void set_level(level_type l) {
m_level |= l;
}
void set_levels(level_type l1, level_type l2) {
level_type i = l1;
while (i <= l2) {
set_level(i);
i *= 2;
}
}
void unset_level(level_type l) {
m_level &= ~l;
}
void set_prefix(const std::string& prefix) {
if (prefix == "") {
m_prefix = prefix;
@@ -129,13 +129,13 @@ public:
m_prefix = prefix + " ";
}
}
logger<level_type>& print() {
websocketLog(m_write_level, m_oss.str()); // Hand to our logger DJS
m_oss.str("");
#if 0
if (test_level(m_write_level)) {
std::cout << m_prefix <<
std::cout << m_prefix <<
boost::posix_time::to_iso_extended_string(
boost::posix_time::second_clock::local_time()
) << " [" << m_write_level << "] " << m_oss.str() << std::endl;
@@ -144,7 +144,7 @@ public:
#endif
return *this;
}
logger<level_type>& at(level_type l) {
m_write_level = l;
return *this;

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_MD5_WRAPPER_HPP
@@ -31,22 +31,22 @@
#include "md5.h"
#include <string>
namespace websocketpp {
namespace websocketpp_02 {
// could be compiled separately
inline std::string md5_hash_string(const std::string& s) {
char digest[16];
md5_state_t state;
md5_init(&state);
md5_append(&state, (const md5_byte_t *)s.c_str(), s.size());
md5_finish(&state, (md5_byte_t *)digest);
std::string ret;
ret.resize(16);
std::copy(digest,digest+16,ret.begin());
return ret;
}
@@ -55,15 +55,15 @@ const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
inline std::string md5_hash_hex(const std::string& input) {
std::string hash = md5_hash_string(input);
std::string hex;
for (size_t i = 0; i < hash.size(); i++) {
hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);
hex.push_back(hexval[(hash[i]) & 0x0F]);
}
return hex;
}
} // websocketpp
} // websocketpp_02
#endif // WEBSOCKETPP_MD5_WRAPPER_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_CONTROL_MESSAGE_HPP
@@ -36,9 +36,9 @@
#include "../utf8_validator/utf8_validator.hpp"
#include "../processors/hybi_util.hpp"
using websocketpp::processor::hybi_util::circshift_prepared_key;
using websocketpp_02::processor::hybi_util::circshift_prepared_key;
namespace websocketpp {
namespace websocketpp_02 {
namespace message {
class control {
@@ -46,55 +46,55 @@ public:
control() {
m_payload.reserve(PAYLOAD_SIZE_INIT);
}
frame::opcode::value get_opcode() const {
return m_opcode;
};
const std::string& get_payload() const {
return m_payload;
}
void process_payload(char *input,uint64_t size) {
const size_t new_size = static_cast<size_t>(m_payload.size() + size);
if (new_size > PAYLOAD_SIZE_MAX) {
throw processor::exception("Message payload was too large.",processor::error::MESSAGE_TOO_BIG);
}
if (m_masked) {
// this retrieves ceiling of size / word size
size_t n = static_cast<size_t>((size + sizeof(size_t) - 1) / sizeof(size_t));
// reinterpret the input as an array of word sized integers
size_t* data = reinterpret_cast<size_t*>(input);
// unmask working buffer
for (size_t i = 0; i < n; i++) {
data[i] ^= m_prepared_key;
}
// circshift working key
m_prepared_key = circshift_prepared_key(m_prepared_key, size%4);
}
// copy working buffer into
m_payload.append(input, static_cast<size_t>(size));
}
void complete() {
if (m_opcode == frame::opcode::CLOSE) {
if (m_payload.size() == 1) {
throw processor::exception("Single byte close code",processor::error::PROTOCOL_VIOLATION);
} else if (m_payload.size() >= 2) {
close::status::value code = close::status::value(get_raw_close_code());
if (close::status::invalid(code)) {
throw processor::exception("Close code is not allowed on the wire.",processor::error::PROTOCOL_VIOLATION);
} else if (close::status::reserved(code)) {
throw processor::exception("Close code is reserved.",processor::error::PROTOCOL_VIOLATION);
}
}
if (m_payload.size() > 2) {
if (!m_validator.decode(m_payload.begin()+2,m_payload.end())) {
@@ -106,14 +106,14 @@ public:
}
}
}
void reset(frame::opcode::value opcode, uint32_t masking_key) {
m_opcode = opcode;
set_masking_key(masking_key);
m_payload.resize(0);
m_validator.reset();
}
close::status::value get_close_code() const {
if (m_payload.size() == 0) {
return close::status::NO_STATUS;
@@ -121,7 +121,7 @@ public:
return close::status::value(get_raw_close_code());
}
}
std::string get_close_reason() const {
if (m_payload.size() > 2) {
return m_payload.substr(2);
@@ -129,7 +129,7 @@ public:
return std::string();
}
}
void set_masking_key(int32_t key) {
m_masking_key.i = key;
m_prepared_key = processor::hybi_util::prepare_masking_key(m_masking_key);
@@ -140,36 +140,36 @@ private:
if (m_payload.size() <= 1) {
throw processor::exception("get_raw_close_code called with invalid size",processor::error::FATAL_ERROR);
}
union {uint16_t i;char c[2];} val;
val.c[0] = m_payload[0];
val.c[1] = m_payload[1];
return ntohs(val.i);
}
static const uint64_t PAYLOAD_SIZE_INIT = 128; // 128B
static const uint64_t PAYLOAD_SIZE_MAX = 128; // 128B
typedef websocketpp::processor::hybi_util::masking_key_type masking_key_type;
typedef websocketpp_02::processor::hybi_util::masking_key_type masking_key_type;
union masking_key {
int32_t i;
char c[4];
};
// Message state
frame::opcode::value m_opcode;
// UTF8 validation state
utf8_validator::validator m_validator;
// Masking state
masking_key_type m_masking_key;
bool m_masked;
size_t m_prepared_key;
// Message payload
std::string m_payload;
};
@@ -177,6 +177,6 @@ private:
typedef boost::shared_ptr<control> control_ptr;
} // namespace message
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_CONTROL_MESSAGE_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include "data.hpp"
@@ -34,14 +34,14 @@
#undef max
#endif // #ifdef max
using websocketpp::message::data;
using websocketpp::processor::hybi_util::circshift_prepared_key;
using websocketpp_02::message::data;
using websocketpp_02::processor::hybi_util::circshift_prepared_key;
data::data(data::pool_ptr p, size_t s) : m_prepared(false),m_index(s),m_ref_count(0),m_pool(p),m_live(false) {
m_payload.reserve(PAYLOAD_SIZE_INIT);
}
websocketpp::frame::opcode::value data::get_opcode() const {
websocketpp_02::frame::opcode::value data::get_opcode() const {
return m_opcode;
}
@@ -52,61 +52,61 @@ const std::string& data::get_header() const {
return m_header;
}
// input must be a buffer with size divisible by the machine word_size and at
// input must be a buffer with size divisible by the machine word_size and at
// least ceil(size/word_size)*word_size bytes long.
void data::process_payload(char *input, size_t size) {
//std::cout << "data message processing: " << size << " bytes" << std::endl;
const size_t new_size = m_payload.size() + size;
if (new_size > PAYLOAD_SIZE_MAX) {
throw processor::exception("Message too big",processor::error::MESSAGE_TOO_BIG);
}
if (new_size > m_payload.capacity()) {
m_payload.reserve(std::max(new_size, 2*m_payload.capacity()));
}
if (m_masked) {
//std::cout << "message is masked" << std::endl;
//std::cout << "before: " << zsutil::to_hex(input, size) << std::endl;
// this retrieves ceiling of size / word size
size_t n = (size + sizeof(size_t) - 1) / sizeof(size_t);
// reinterpret the input as an array of word sized integers
size_t* data = reinterpret_cast<size_t*>(input);
// unmask working buffer
for (size_t i = 0; i < n; i++) {
data[i] ^= m_prepared_key;
}
//std::cout << "after: " << zsutil::to_hex(input, size) << std::endl;
// circshift working key
//std::cout << "circshift by : " << size%4 << " bytes " << zsutil::to_hex(reinterpret_cast<char*>(&m_prepared_key),sizeof(size_t));
m_prepared_key = circshift_prepared_key(m_prepared_key, size%4);
//std::cout << " to " << zsutil::to_hex(reinterpret_cast<char*>(&m_prepared_key),sizeof(size_t)) << std::endl;
}
if (m_opcode == frame::opcode::TEXT) {
if (!m_validator.decode(input, input+size)) {
throw processor::exception("Invalid UTF8 data",
processor::error::PAYLOAD_VIOLATION);
}
}
// copy working buffer into
//std::cout << "before: " << m_payload.size() << std::endl;
m_payload.append(input, size);
//std::cout << "after: " << m_payload.size() << std::endl;
}
void data::reset(websocketpp::frame::opcode::value opcode) {
void data::reset(websocketpp_02::frame::opcode::value opcode) {
m_opcode = opcode;
m_masked = false;
m_payload.clear();
@@ -128,7 +128,7 @@ void data::validate_payload() {
if (!m_validator.decode(m_payload.begin(), m_payload.end())) {
throw exception("Invalid UTF8 data",error::PAYLOAD_VIOLATION);
}
if (!m_validator.complete()) {
throw exception("Invalid UTF8 data",error::PAYLOAD_VIOLATION);
}
@@ -146,7 +146,7 @@ void data::set_prepared(bool b) {
}
bool data::get_prepared() const {
return m_prepared;
return m_prepared;
}
// This could be further optimized using methods that write directly into the
@@ -162,30 +162,30 @@ void data::append_payload(const std::string& payload) {
void data::mask() {
if (m_masked && m_payload.size() > 0) {
// By default WebSocket++ performs block masking/unmasking in a mannor that makes
// some assumptions about the nature of the machine and STL library used. In
// some assumptions about the nature of the machine and STL library used. In
// particular the assumption is either a 32 or 64 bit word size and an STL with
// std::string::data returning a contiguous char array.
//
// This method improves performance by 3-8x depending on the ratio of small to
// This method improves performance by 3-8x depending on the ratio of small to
// large messages and the availability of a 64 bit processor.
//
// To disable this optimization (for use with alternative STL implementations or
// processors) define WEBSOCKETPP_STRICT_MASKING when compiling the library. This
// will force the library to perform masking in single byte chunks.
//#define WEBSOCKETPP_STRICT_MASKING
#ifdef WEBSOCKETPP_STRICT_MASKING
size_t len = m_payload.size();
for (size_t i = 0; i < len; i++) {
m_payload[i] ^= m_masking_key.c[i%4];
}
#else
// This should trigger a write to the string in case the STL
// This should trigger a write to the string in case the STL
// implimentation is copy-on-write and hasn't been written to yet.
// Performing the masking will always require a copy of the string
// Performing the masking will always require a copy of the string
// in this case to hold the masked version.
m_payload[0] = m_payload[0];
size_t size = m_payload.size()/sizeof(size_t);
size_t key = m_masking_key.i;
size_t wordSize = sizeof(size_t);

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_DATA_MESSAGE_HPP
@@ -49,7 +49,7 @@
#include <queue>
#include <vector>
namespace websocketpp {
namespace websocketpp_02 {
namespace message {
/// message::pool impliments a reference counted pool of elements.
@@ -71,32 +71,32 @@ public:
typedef boost::weak_ptr<type> weak_ptr;
typedef typename element_type::ptr element_ptr;
typedef boost::function<void()> callback_type;
pool(size_t max_elements) : m_cur_elements(0),m_max_elements(max_elements) {}
~pool() {}
// copy/assignment constructors require C++11
// boost::noncopyable is being used in the meantime.
// pool(pool const&) = delete;
// pool& operator=(pool const&) = delete
/// Requests a pointer to the next free element in the resource pool.
/* If there isn't a free element a new one is created. If the maximum number
* of elements has been created then it returns an empty/null element
* of elements has been created then it returns an empty/null element
* pointer.
*/
element_ptr get() {
element_ptr p, q;
{
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
/*std::cout << "message requested ("
/*std::cout << "message requested ("
<< m_cur_elements-m_avaliable.size()
<< "/"
<< m_cur_elements
<< ")"
<< std::endl;*/
if (!m_avaliable.empty()) {
p = m_avaliable.front(); // FIXME can call intrusive_ptr_add_ref (line 215) which can deadlock
q = p;
@@ -106,59 +106,59 @@ public:
if (m_cur_elements == m_max_elements) {
return element_ptr();
}
p = element_ptr(new element_type(type::shared_from_this(),m_cur_elements));
m_cur_elements++;
m_used.push_back(p);
/*std::cout << "Allocated new data message. Count is now "
/*std::cout << "Allocated new data message. Count is now "
<< m_cur_elements
<< std::endl;*/
}
p->set_live();
}
return p;
}
void recycle(element_ptr p) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
if (p->get_index()+1 > m_used.size() || m_used[p->get_index()] != p) {
//std::cout << "error tried to recycle a pointer we don't control" << std::endl;
// error tried to recycle a pointer we don't control
return;
}
m_avaliable.push(p);
m_used[p->get_index()] = element_ptr();
/*std::cout << "message recycled ("
/*std::cout << "message recycled ("
<< m_cur_elements-m_avaliable.size()
<< "/"
<< m_cur_elements
<< ")"
<< std::endl;*/
if (m_callback && m_avaliable.size() == 1) {
m_callback();
}
}
// set a function that will be called when new elements are avaliable.
void set_callback(callback_type fn) {
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
m_callback = fn;
}
private:
size_t m_cur_elements;
size_t m_max_elements;
std::queue<element_ptr> m_avaliable;
std::vector<element_ptr> m_used;
callback_type m_callback;
boost::recursive_mutex m_lock;
};
@@ -167,19 +167,19 @@ public:
typedef boost::intrusive_ptr<data> ptr;
typedef pool<data>::ptr pool_ptr;
typedef pool<data>::weak_ptr pool_weak_ptr;
data(pool_ptr p, size_t s);
void reset(websocketpp::frame::opcode::value opcode);
void reset(websocketpp_02::frame::opcode::value opcode);
frame::opcode::value get_opcode() const;
const std::string& get_payload() const;
const std::string& get_header() const;
// ##reading##
// sets the masking key to be used to unmask as bytes are read.
void set_masking_key(int32_t key);
// read at most size bytes from a payload stream and perform unmasking/utf8
// validation. Returns number of bytes read.
// throws a processor::exception if the message is too big, there is a fatal
@@ -188,76 +188,76 @@ public:
void process_payload(char * input, size_t size);
void complete();
void validate_payload();
// ##writing##
// sets the payload to payload. Performs max size and UTF8 validation
// sets the payload to payload. Performs max size and UTF8 validation
// immediately and throws processor::exception if it fails
void set_payload(const std::string& payload);
void append_payload(const std::string& payload);
void set_header(const std::string& header);
// Performs masking and header generation if it has not been done already.
void set_prepared(bool b);
bool get_prepared() const;
void mask();
int32_t get_masking_key() const {
return m_masking_key.i;
}
// pool management interface
void set_live();
size_t get_index() const;
private:
static const uint64_t PAYLOAD_SIZE_INIT = 1000; // 1KB
static const uint64_t PAYLOAD_SIZE_MAX = 100000000;// 100MB
typedef websocketpp::processor::hybi_util::masking_key_type masking_key_type;
typedef websocketpp_02::processor::hybi_util::masking_key_type masking_key_type;
friend void intrusive_ptr_add_ref(const data * s) {
boost::unique_lock<boost::recursive_mutex> lock(s->m_lock);
++s->m_ref_count;
}
friend void intrusive_ptr_release(const data * s) {
boost::unique_lock<boost::recursive_mutex> lock(s->m_lock);
// TODO: thread safety
long count = --s->m_ref_count;
if (count == 1 && s->m_live) {
// recycle if endpoint exists
s->m_live = false;
pool_ptr pp = s->m_pool.lock();
if (pp) {
lock.unlock();
pp->recycle(ptr(const_cast<data *>(s)));
}
//s->m_pool->recycle(ptr(const_cast<data *>(s)));
} else if (count == 0) {
lock.unlock();
boost::checked_delete(static_cast<data const *>(s));
}
}
// Message state
frame::opcode::value m_opcode;
// UTF8 validation state
utf8_validator::validator m_validator;
// Masking state
masking_key_type m_masking_key;
bool m_masked;
size_t m_prepared_key;
std::string m_header;
std::string m_payload;
bool m_prepared;
// reference counting
size_t m_index;
mutable boost::detail::atomic_count m_ref_count;
@@ -267,8 +267,8 @@ private:
};
typedef boost::intrusive_ptr<data> data_ptr;
} // namespace message
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_DATA_MESSAGE_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_PROCESSOR_HYBI_HPP
@@ -44,7 +44,7 @@
#undef min
#endif // #ifdef min
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
namespace hybi_state {
@@ -91,11 +91,11 @@ std::list< std::pair< std::string,std::string > >
/*class hybi_message {
public:
hybi_message(frame::opcode::value opcode) : m_processed(false) {
}
void reset() {
}
private:
bool m_processed;
@@ -112,37 +112,37 @@ private:
template <class connection_type>
class hybi : public processor_base {
public:
hybi(connection_type &connection)
hybi(connection_type &connection)
: m_connection(connection),
m_write_frame(connection)
{
reset();
}
}
void validate_handshake(const http::parser::request& request) const {
std::stringstream err;
std::string h;
if (request.method() != "GET") {
err << "Websocket handshake has invalid method: "
err << "Websocket handshake has invalid method: "
<< request.method();
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
}
// TODO: allow versions greater than 1.1
if (request.version() != "HTTP/1.1") {
err << "Websocket handshake has invalid HTTP version: "
err << "Websocket handshake has invalid HTTP version: "
<< request.method();
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
}
// verify the presence of required headers
if (request.header("Host") == "") {
throw(http::exception("Required Host header is missing",http::status_code::BAD_REQUEST));
}
h = request.header("Upgrade");
if (h == "") {
throw(http::exception("Required Upgrade header is missing",http::status_code::BAD_REQUEST));
@@ -150,26 +150,26 @@ public:
err << "Upgrade header \"" << h << "\", does not contain required token \"websocket\"";
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
}
h = request.header("Connection");
if (h == "") {
throw(http::exception("Required Connection header is missing",http::status_code::BAD_REQUEST));
} else if (!boost::ifind_first(h,"upgrade")) {
err << "Connection header, \"" << h
err << "Connection header, \"" << h
<< "\", does not contain required token \"upgrade\"";
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
}
if (request.header("Sec-WebSocket-Key") == "") {
throw(http::exception("Required Sec-WebSocket-Key header is missing",http::status_code::BAD_REQUEST));
}
h = request.header("Sec-WebSocket-Version");
if (h == "") {
throw(http::exception("Required Sec-WebSocket-Version header is missing",http::status_code::BAD_REQUEST));
} else {
int version = atoi(h.c_str());
if (version != 7 && version != 8 && version != 13) {
err << "This processor doesn't support WebSocket protocol version "
<< version;
@@ -177,11 +177,11 @@ public:
}
}
}
std::string get_origin(const http::parser::request& request) const {
std::string h = request.header("Sec-WebSocket-Version");
int version = atoi(h.c_str());
if (version == 13) {
return request.header("Origin");
} else if (version == 7 || version == 8) {
@@ -190,18 +190,18 @@ public:
throw(http::exception("Could not determine origin header. Check Sec-WebSocket-Version header",http::status_code::BAD_REQUEST));
}
}
uri_ptr get_uri(const http::parser::request& request) const {
std::string h = request.header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return uri_ptr(new uri(m_connection.is_secure(),h,request.uri()));
@@ -211,46 +211,46 @@ public:
h.substr(last_colon+1),
request.uri()));
}
// TODO: check if get_uri is a full uri
}
void handshake_response(const http::parser::request& request,
http::parser::response& response)
http::parser::response& response)
{
std::string server_key = request.header("Sec-WebSocket-Key");
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
uint32_t message_digest[5];
sha.Reset();
sha << server_key.c_str();
if (sha.Result(message_digest)){
// convert sha1 hash bytes to network byte order because this sha1
// library works on ints rather than bytes
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
server_key = base64_encode(
reinterpret_cast<const unsigned char*>
(message_digest),20
);
// set handshake accept headers
response.replace_header("Sec-WebSocket-Accept",server_key);
response.add_header("Upgrade","websocket");
response.add_header("Connection","Upgrade");
} else {
//m_endpoint->elog().at(log::elevel::RERROR)
//m_endpoint->elog().at(log::elevel::RERROR)
//<< "Error computing handshake sha1 hash" << log::endl;
// TODO: make sure this error path works
response.set_status(http::status_code::INTERNAL_SERVER_ERROR);
}
}
void consume(std::istream& s) {
while (s.good() && m_state != hybi_state::READY) {
try {
@@ -267,11 +267,11 @@ public:
case hybi_state::IGNORE:
s.ignore(m_payload_left);
m_payload_left -= static_cast<size_t>(s.gcount());
if (m_payload_left == 0) {
reset();
}
break;
default:
break;
@@ -279,8 +279,8 @@ public:
} catch (const processor::exception& e) {
if (e.code() != processor::error::OUT_OF_MESSAGES) {
// The out of messages exception acts as an inturrupt rather
// than an error. In that case we don't want to reset
// processor state. In all other cases we are aborting
// than an error. In that case we don't want to reset
// processor state. In all other cases we are aborting
// processing of the message in flight and want to reset the
// processor for a new message.
if (m_header.ready()) {
@@ -288,24 +288,24 @@ public:
ignore();
}
}
throw e;
}
}
}
// Sends the processor an inturrupt signal instructing it to ignore the next
// num bytes and then reset itself. This is used to flush a bad frame out of
// the read buffer.
void ignore() {
m_state = hybi_state::IGNORE;
}
void process_header(std::istream& s) {
m_header.consume(s);
if (m_header.ready()) {
// Get a free message from the read queue for the type of the
// Get a free message from the read queue for the type of the
// current message
if (m_header.is_control()) {
process_control_header();
@@ -314,40 +314,40 @@ public:
}
}
}
void process_control_header() {
m_control_message = m_connection.get_control_message();
if (!m_control_message) {
throw processor::exception("Out of control messages",
processor::error::OUT_OF_MESSAGES);
}
m_control_message->reset(m_header.get_opcode(),m_header.get_masking_key());
m_payload_left = static_cast<size_t>(m_header.get_payload_size());
if (m_payload_left == 0) {
process_frame();
} else {
m_state = hybi_state::READ_PAYLOAD;
}
}
void process_data_header() {
if (!m_data_message) {
// This is a new message. No continuation frames allowed.
if (m_header.get_opcode() == frame::opcode::CONTINUATION) {
throw processor::exception("Received continuation frame without an outstanding message.",processor::error::PROTOCOL_VIOLATION);
}
m_data_message = m_connection.get_data_message();
if (!m_data_message) {
throw processor::exception("Out of data messages",
processor::error::OUT_OF_MESSAGES);
}
m_data_message->reset(m_header.get_opcode());
} else {
// A message has already been started. Continuation frames only!
@@ -355,9 +355,9 @@ public:
throw processor::exception("Received new message before the completion of the existing one.",processor::error::PROTOCOL_VIOLATION);
}
}
m_payload_left = static_cast<size_t>(m_header.get_payload_size());
if (m_payload_left == 0) {
process_frame();
} else {
@@ -366,28 +366,28 @@ public:
m_state = hybi_state::READ_PAYLOAD;
}
}
void process_payload(std::istream& input) {
//std::cout << "payload left 1: " << m_payload_left << std::endl;
size_t num;
// read bytes into processor buffer. Read the lesser of the buffer size
// and the number of bytes left in the payload.
input.read(m_payload_buffer, std::min(m_payload_left, PAYLOAD_BUFFER_SIZE));
num = static_cast<size_t>(input.gcount());
if (input.bad()) {
throw processor::exception("istream readsome error",
processor::error::FATAL_ERROR);
}
if (num == 0) {
return;
}
m_payload_left -= num;
// tell the appropriate message to process the bytes.
if (m_header.is_control()) {
m_control_message->process_payload(m_payload_buffer,num);
@@ -395,13 +395,13 @@ public:
//m_connection.alog().at(log::alevel::DEVEL) << "process_payload. Size: " << m_payload_left << log::endl;
m_data_message->process_payload(m_payload_buffer,num);
}
if (m_payload_left == 0) {
process_frame();
}
}
void process_frame() {
if (m_header.get_fin()) {
if (m_header.is_control()) {
@@ -414,34 +414,34 @@ public:
reset();
}
}
bool ready() const {
return m_state == hybi_state::READY;
}
bool is_control() const {
return m_header.is_control();
}
// note this can only be called once
message::data_ptr get_data_message() {
message::data_ptr p = m_data_message;
m_data_message.reset();
return p;
}
// note this can only be called once
message::control_ptr get_control_message() {
message::control_ptr p = m_control_message;
m_control_message.reset();
return p;
}
void reset() {
m_state = hybi_state::READ_HEADER;
m_header.reset();
}
uint64_t get_bytes_needed() const {
switch (m_state) {
case hybi_state::READ_HEADER:
@@ -455,8 +455,8 @@ public:
throw "shouldn't be here";
}
}
// TODO: replace all this to remove all lingering dependencies on
// TODO: replace all this to remove all lingering dependencies on
// websocket_frame
binary_string_ptr prepare_frame(frame::opcode::value opcode,
bool mask,
@@ -465,37 +465,37 @@ public:
// TODO: hybi_legacy doesn't allow non-text frames.
throw;
}*/
// TODO: utf8 validation on payload.
binary_string_ptr response(new binary_string(0));
m_write_frame.reset();
m_write_frame.set_opcode(opcode);
m_write_frame.set_masked(mask);
m_write_frame.set_fin(true);
m_write_frame.set_payload(payload);
m_write_frame.process_payload();
// TODO
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
// copy header
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
// copy payload
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
return response;
}
binary_string_ptr prepare_frame(frame::opcode::value opcode,
bool mask,
const binary_string& payload) {
@@ -503,86 +503,86 @@ public:
// TODO: hybi_legacy doesn't allow non-text frames.
throw;
}*/
// TODO: utf8 validation on payload.
binary_string_ptr response(new binary_string(0));
m_write_frame.reset();
m_write_frame.set_opcode(opcode);
m_write_frame.set_masked(mask);
m_write_frame.set_fin(true);
m_write_frame.set_payload(payload);
m_write_frame.process_payload();
// TODO
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
// copy header
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
// copy payload
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
return response;
}
/*binary_string_ptr prepare_close_frame(close::status::value code,
bool mask,
const std::string& reason) {
binary_string_ptr response(new binary_string(0));
m_write_frame.reset();
m_write_frame.set_opcode(frame::opcode::CLOSE);
m_write_frame.set_masked(mask);
m_write_frame.set_fin(true);
m_write_frame.set_status(code,reason);
m_write_frame.process_payload();
// TODO
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
// copy header
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
// copy payload
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
return response;
}*/
// new prepare frame stuff
void prepare_frame(message::data_ptr msg) {
assert(msg);
if (msg->get_prepared()) {
return;
}
msg->validate_payload();
bool masked = !m_connection.is_server();
int32_t key = m_connection.rand();
m_write_header.reset();
m_write_header.set_fin(true);
m_write_header.set_opcode(msg->get_opcode());
m_write_header.set_masked(masked,key);
m_write_header.set_payload_size(msg->get_payload().size());
m_write_header.complete();
msg->set_header(m_write_header.get_header_bytes());
if (masked) {
msg->set_masking_key(key);
msg->mask();
}
msg->set_prepared(true);
}
void prepare_close_frame(message::data_ptr msg,
void prepare_close_frame(message::data_ptr msg,
close::status::value code,
const std::string& reason)
{
@@ -590,15 +590,15 @@ public:
if (msg->get_prepared()) {
return;
}
// set close payload
if (code != close::status::NO_STATUS) {
const uint16_t payload = htons(static_cast<u_short>(code));
msg->set_payload(std::string(reinterpret_cast<const char*>(&payload), 2));
msg->append_payload(reason);
}
// prepare rest of frame
prepare_frame(msg);
}
@@ -606,25 +606,25 @@ private:
// must be divisible by 8 (some things are hardcoded for 4 and 8 byte word
// sizes
static const size_t PAYLOAD_BUFFER_SIZE = 512;
connection_type& m_connection;
int m_state;
message::data_ptr m_data_message;
message::control_ptr m_control_message;
hybi_header m_header;
hybi_header m_write_header;
size_t m_payload_left;
char m_payload_buffer[PAYLOAD_BUFFER_SIZE];
frame::parser<connection_type> m_write_frame; // TODO: refactor this out
};
};
template <class connection_type>
const size_t hybi<connection_type>::PAYLOAD_BUFFER_SIZE;
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_PROCESSOR_HYBI_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,14 +22,14 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include "hybi_header.hpp"
#include <cstring>
using websocketpp::processor::hybi_header;
using websocketpp_02::processor::hybi_header;
hybi_header::hybi_header() {
reset();
@@ -46,14 +46,14 @@ void hybi_header::consume(std::istream& input) {
case STATE_BASIC_HEADER:
input.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],
m_bytes_needed);
m_bytes_needed -= input.gcount();
if (m_bytes_needed == 0) {
process_basic_header();
validate_basic_header();
if (m_bytes_needed > 0) {
m_state = STATE_EXTENDED_HEADER;
} else {
@@ -65,9 +65,9 @@ void hybi_header::consume(std::istream& input) {
case STATE_EXTENDED_HEADER:
input.read(&m_header[get_header_len()-m_bytes_needed],
m_bytes_needed);
m_bytes_needed -= input.gcount();
if (m_bytes_needed == 0) {
process_extended_header();
m_state = STATE_READY;
@@ -98,7 +98,7 @@ void hybi_header::set_rsv2(bool b) {
void hybi_header::set_rsv3(bool b) {
set_header_bit(BPB0_RSV3,0,b);
}
void hybi_header::set_opcode(websocketpp::frame::opcode::value op) {
void hybi_header::set_opcode(websocketpp_02::frame::opcode::value op) {
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
m_header[0] |= op; // set op bits
}
@@ -126,7 +126,7 @@ void hybi_header::set_payload_size(uint64_t size) {
}
m_payload_size = size;
*(reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])) = htons(static_cast<uint16_t>(size));
/* uint16_t net_size = htons(static_cast<uint16_t>(size));
//memcpy(&m_header[BASIC_HEADER_LENGTH], &net_size, sizeof(uint16_t));
std::copy(
@@ -148,7 +148,7 @@ void hybi_header::set_payload_size(uint64_t size) {
} else {
throw processor::exception("set_payload_size called with value that was too large (>2^63)",processor::error::MESSAGE_TOO_BIG);
}
}
void hybi_header::complete() {
validate_basic_header();
@@ -173,7 +173,7 @@ bool hybi_header::get_rsv2() const {
bool hybi_header::get_rsv3() const {
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
}
websocketpp::frame::opcode::value hybi_header::get_opcode() const {
websocketpp_02::frame::opcode::value hybi_header::get_opcode() const {
return frame::opcode::value(m_header[0] & BPB0_OPCODE);
}
bool hybi_header::get_masked() const {
@@ -196,17 +196,17 @@ bool hybi_header::is_control() const {
// private
unsigned int hybi_header::get_header_len() const {
unsigned int temp = 2;
if (get_masked()) {
temp += 4;
}
if (get_basic_size() == 126) {
temp += 2;
} else if (get_basic_size() == 127) {
temp += 8;
}
return temp;
}
@@ -214,27 +214,27 @@ uint8_t hybi_header::get_basic_size() const {
return m_header[1] & BPB1_PAYLOAD;
}
void hybi_header::validate_basic_header() const {
void hybi_header::validate_basic_header() const {
// check for control frame size
if (is_control() && get_basic_size() > frame::limits::PAYLOAD_SIZE_BASIC) {
throw processor::exception("Control Frame is too large",processor::error::PROTOCOL_VIOLATION);
}
// check for reserved bits
if (get_rsv1() || get_rsv2() || get_rsv3()) {
throw processor::exception("Reserved bit used",processor::error::PROTOCOL_VIOLATION);
}
// check for reserved opcodes
if (frame::opcode::reserved(get_opcode())) {
throw processor::exception("Reserved opcode used",processor::error::PROTOCOL_VIOLATION);
}
// check for invalid opcodes
if (frame::opcode::invalid(get_opcode())) {
throw processor::exception("Invalid opcode used",processor::error::PROTOCOL_VIOLATION);
}
// check for fragmented control message
if (is_control() && !get_fin()) {
throw processor::exception("Fragmented control message",processor::error::PROTOCOL_VIOLATION);
@@ -246,34 +246,34 @@ void hybi_header::process_basic_header() {
}
void hybi_header::process_extended_header() {
uint8_t s = get_basic_size();
if (s <= frame::limits::PAYLOAD_SIZE_BASIC) {
m_payload_size = s;
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
// reinterpret the second two bytes as a 16 bit integer in network
// byte order. Convert to host byte order and store locally.
m_payload_size = ntohs(*(
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (m_payload_size < s) {
std::stringstream err;
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << m_payload_size;
throw processor::exception(err.str(),processor::error::PROTOCOL_VIOLATION);
}
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
// reinterpret the second eight bytes as a 64 bit integer in
// reinterpret the second eight bytes as a 64 bit integer in
// network byte order. Convert to host byte order and store.
m_payload_size = zsutil::ntohll(*(
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (m_payload_size <= frame::limits::PAYLOAD_SIZE_EXTENDED) {
throw processor::exception("payload length not minimally encoded",
processor::error::PROTOCOL_VIOLATION);
}
} else {
// TODO: shouldn't be here how to handle?
throw processor::exception("invalid get_basic_size in process_extended_header");

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_PROCESSOR_HYBI_HEADER_HPP
@@ -30,26 +30,26 @@
#include "processor.hpp"
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
/// Describes a processor for reading and writing WebSocket frame headers
/**
* The hybi_header class provides a processor capable of reading and writing
* WebSocket frame headers. It has two writing modes and two reading modes.
*
*
* Writing method 1: call consume() until ready()
* Writing method 2: call set_* methods followed by complete()
*
* Writing methods are valid only when ready() returns false. Use reset() to
*
* Writing methods are valid only when ready() returns false. Use reset() to
* reset the header for writing again. Mixing writing methods between calls to
* reset() may behave unpredictably.
*
*
* Reading method 1: call get_header_bytes() to return a string of bytes
* Reading method 2: call get_* methods to read individual values
*
*
* Reading methods are valid only when ready() is true.
*
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe
@@ -60,7 +60,7 @@ public:
hybi_header();
/// Reset a header processor for writing
void reset();
// Writing interface (parse a byte stream)
// valid only if ready() returns false
// Consume will throw a processor::exception in the case that the bytes it
@@ -68,7 +68,7 @@ public:
void consume(std::istream& input);
uint64_t get_bytes_needed() const;
bool ready() const;
// Writing interface (set fields directly)
// valid only if ready() returns false
// set_* may allow invalid values. Call complete() once values are set to
@@ -77,17 +77,17 @@ public:
void set_rsv1(bool b);
void set_rsv2(bool b);
void set_rsv3(bool b);
void set_opcode(websocketpp::frame::opcode::value op);
void set_opcode(websocketpp_02::frame::opcode::value op);
void set_masked(bool masked,int32_t key);
void set_payload_size(uint64_t size);
// Complete will throw a processor::exception in the case that the
// Complete will throw a processor::exception in the case that the
// combination of values set do not form a valid WebSocket frame header.
void complete();
// Reading interface (get string of bytes)
// valid only if ready() returns true
std::string get_header_bytes() const;
// Reading interface (get fields directly)
// valid only if ready() returns true
bool get_fin() const;
@@ -100,21 +100,21 @@ public:
// a masking key of zero is slightly different than no mask at all.
int32_t get_masking_key() const;
uint64_t get_payload_size() const;
bool is_control() const;
private:
// general helper functions
unsigned int get_header_len() const;
uint8_t get_basic_size() const;
void validate_basic_header() const;
// helper functions for writing
void process_basic_header();
void process_extended_header();
void set_header_bit(uint8_t bit,int byte,bool value);
void set_masking_key(int32_t key);
void clear_masking_key();
// basic payload byte flags
static const uint8_t BPB0_OPCODE = 0x0F;
static const uint8_t BPB0_RSV3 = 0x10;
@@ -123,25 +123,25 @@ private:
static const uint8_t BPB0_FIN = 0x80;
static const uint8_t BPB1_PAYLOAD = 0x7F;
static const uint8_t BPB1_MASK = 0x80;
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
static const unsigned int BASIC_HEADER_LENGTH = 2;
static const unsigned int BASIC_HEADER_LENGTH = 2;
static const unsigned int MAX_HEADER_LENGTH = 14;
static const uint8_t STATE_BASIC_HEADER = 1;
static const uint8_t STATE_EXTENDED_HEADER = 2;
static const uint8_t STATE_READY = 3;
static const uint8_t STATE_WRITE = 4;
uint8_t m_state;
std::streamsize m_bytes_needed;
uint64_t m_payload_size;
char m_header[MAX_HEADER_LENGTH];
};
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_PROCESSOR_HYBI_HEADER_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_PROCESSOR_HYBI_LEGACY_HPP
@@ -39,7 +39,7 @@
#undef min
#endif // #ifdef min
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
namespace hybi_legacy_state {
@@ -53,26 +53,26 @@ namespace hybi_legacy_state {
template <class connection_type>
class hybi_legacy : public processor_base {
public:
hybi_legacy(connection_type &connection)
hybi_legacy(connection_type &connection)
: m_connection(connection),
m_state(hybi_legacy_state::INIT)
m_state(hybi_legacy_state::INIT)
{
reset();
}
void validate_handshake(const http::parser::request& /*headers*/) const {
}
void handshake_response(const http::parser::request& request,http::parser::response& response) {
char key_final[16];
// copy key1 into final key
decode_client_key(request.header("Sec-WebSocket-Key1"), &key_final[0]);
// copy key2 into final key
decode_client_key(request.header("Sec-WebSocket-Key2"), &key_final[4]);
// copy key3 into final key
// key3 should be exactly 8 bytes. If it is more it will be truncated
// if it is less the final key will almost certainly be wrong.
@@ -82,20 +82,20 @@ public:
std::copy(key3.c_str(),
key3.c_str()+std::min(static_cast<size_t>(8), key3.size()),
&key_final[8]);
m_key3 = md5_hash_string(std::string(key_final,16));
response.add_header("Upgrade","websocket");
response.add_header("Connection","Upgrade");
// TODO: require headers that need application specific information?
// Echo back client's origin unless our local application set a
// more restrictive one.
if (response.header("Sec-WebSocket-Origin") == "") {
response.add_header("Sec-WebSocket-Origin",request.header("Origin"));
}
// Echo back the client's request host unless our local application
// set a different one.
if (response.header("Sec-WebSocket-Location") == "") {
@@ -104,22 +104,22 @@ public:
response.add_header("Sec-WebSocket-Location",uri->str());
}
}
std::string get_origin(const http::parser::request& request) const {
return request.header("Origin");
}
uri_ptr get_uri(const http::parser::request& request) const {
std::string h = request.header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return uri_ptr(new uri(m_connection.is_secure(),h,request.uri()));
@@ -129,10 +129,10 @@ public:
h.substr(last_colon+1),
request.uri()));
}
// TODO: check if get_uri is a full uri
}
void consume(std::istream& s) {
//unsigned char c;
while (s.good() && m_state != hybi_legacy_state::DONE) {
@@ -142,91 +142,91 @@ public:
//}
}
}
bool ready() const {
return m_state == hybi_legacy_state::DONE;
}
// legacy hybi has no control messages.
bool is_control() const {
return false;
}
message::data_ptr get_data_message() {
message::data_ptr p = m_data_message;
m_data_message.reset();
return p;
}
message::control_ptr get_control_message() {
throw "Hybi legacy has no control messages.";
}
void process(std::istream& input) {
if (m_state == hybi_legacy_state::INIT) {
// we are looking for a 0x00
if (input.peek() == 0x00) {
// start a message
input.ignore();
m_state = hybi_legacy_state::READ;
m_data_message = m_connection.get_data_message();
if (!m_data_message) {
throw processor::exception("Out of data messages",processor::error::OUT_OF_MESSAGES);
}
m_data_message->reset(frame::opcode::TEXT);
} else {
input.ignore();
// TODO: ignore or error
//std::stringstream foo;
//foo << "invalid character read: |" << input.peek() << "|";
std::cout << "invalid character read: |" << input.peek() << "|" << std::endl;
//throw processor::exception(foo.str(),processor::error::PROTOCOL_VIOLATION);
}
} else if (m_state == hybi_legacy_state::READ) {
if (input.peek() == 0xFF) {
// end
input.ignore();
m_state = hybi_legacy_state::DONE;
} else {
if (m_data_message) {
size_t num;
input.get(m_payload_buffer, PAYLOAD_BUFFER_SIZE, '\xFF');
num = static_cast<size_t>(input.gcount());
if (input.bad()) {
throw processor::exception("istream readsome error",
processor::error::FATAL_ERROR);
}
m_data_message->process_payload(m_payload_buffer,num);
}
}
}
}
void reset() {
m_state = hybi_legacy_state::INIT;
m_data_message.reset();
}
uint64_t get_bytes_needed() const {
return 1;
}
std::string get_key3() const {
return m_key3;
}
// TODO: to factor away
binary_string_ptr prepare_frame(frame::opcode::value opcode,
bool mask,
@@ -235,20 +235,20 @@ public:
// TODO: hybi_legacy doesn't allow non-text frames.
throw;
}
// TODO: mask = ignore?
// TODO: utf8 validation on payload.
binary_string_ptr response(new binary_string(payload.size()+2));
(*response)[0] = 0x00;
std::copy(payload.begin(),payload.end(),response->begin()+1);
(*response)[response->size()-1] = 0xFF;
return response;
}
binary_string_ptr prepare_frame(frame::opcode::value opcode,
bool mask,
const utf8_string& payload) {
@@ -256,37 +256,37 @@ public:
// TODO: hybi_legacy doesn't allow non-text frames.
throw;
}
// TODO: mask = ignore?
// TODO: utf8 validation on payload.
binary_string_ptr response(new binary_string(payload.size()+2));
(*response)[0] = 0x00;
std::copy(payload.begin(),payload.end(),response->begin()+1);
(*response)[response->size()-1] = 0xFF;
return response;
}
binary_string_ptr prepare_close_frame(close::status::value code,
bool mask,
const std::string& reason) {
binary_string_ptr response(new binary_string(2));
(*response)[0] = 0xFF;
(*response)[1] = 0x00;
return response;
}
void prepare_frame(message::data_ptr msg) {
assert(msg);
if (msg->get_prepared()) {
return;
}
msg->set_header(std::string(1,0x00));
struct Marker
@@ -298,7 +298,7 @@ public:
char c;
unsigned char uc;
} v;
v.uc = 0xff;
value = std::string (1, v.c);
@@ -308,10 +308,10 @@ public:
};
static Marker marker;
msg->append_payload(marker.value);
msg->set_prepared(true);
}
void prepare_close_frame(message::data_ptr msg,
close::status::value /*code*/,
const std::string& /*reason*/)
@@ -320,9 +320,9 @@ public:
if (msg->get_prepared()) {
return;
}
msg->set_header(std::string());
struct Marker
{
Marker () { value.uc = 0xff; }
@@ -337,16 +337,16 @@ public:
val.append(1,marker.value.c);
val.append(1,0x00);
msg->set_payload(val);
msg->set_prepared(true);
}
private:
void decode_client_key(const std::string& key, char* result) {
int spaces = 0;
std::string digits = "";
uint32_t num;
// key2
for (size_t i = 0; i < key.size(); i++) {
if (key[i] == ' ') {
@@ -355,7 +355,7 @@ private:
digits += key[i];
}
}
num = atoi(digits.c_str());
if (spaces > 0 && num > 0) {
num = htonl(num/spaces);
@@ -366,22 +366,22 @@ private:
std::fill(result,result+4,0);
}
}
// must be divisible by 8 (some things are hardcoded for 4 and 8 byte word
// sizes
static const size_t PAYLOAD_BUFFER_SIZE = 512;
connection_type& m_connection;
hybi_legacy_state::value m_state;
message::data_ptr m_data_message;
std::string m_key3;
char m_payload_buffer[PAYLOAD_BUFFER_SIZE];
};
} // processor
} // websocketpp
} // websocketpp_02
#endif // WEBSOCKET_PROCESSOR_HYBI_LEGACY_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,14 +22,14 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include "hybi_util.hpp"
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
namespace hybi_util {
namespace hybi_util {
size_t prepare_masking_key(const masking_key_type& key) {
size_t prepared_key = key.i;
@@ -50,11 +50,11 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key) {
size_t prepared_key = prepare_masking_key(key);
size_t n = length/sizeof(size_t);
size_t* word_data = reinterpret_cast<size_t*>(data);
for (size_t i = 0; i < n; i++) {
word_data[i] ^= prepared_key;
}
for (size_t i = n*sizeof(size_t); i < length; i++) {
data[i] ^= key.c[i%4];
}
@@ -62,4 +62,4 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key) {
} // namespace hybi_util
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_HYBI_UTIL_HPP
@@ -30,9 +30,9 @@
#include "../common.hpp"
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
namespace hybi_util {
namespace hybi_util {
// type used to store a masking key
union masking_key_type {
@@ -65,6 +65,6 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key);
} // namespace hybi_util
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_HYBI_UTIL_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_PROCESSOR_HPP
@@ -31,9 +31,9 @@
#include <exception>
#include <string>
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
namespace error {
enum value {
FATAL_ERROR = 0, // force session end
@@ -47,27 +47,27 @@ namespace error {
}
class exception : public std::exception {
public:
public:
exception(const std::string& msg,
error::value code = error::FATAL_ERROR)
error::value code = error::FATAL_ERROR)
: m_msg(msg),m_code(code) {}
~exception() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
error::value code() const throw() {
return m_code;
}
std::string m_msg;
error::value m_code;
};
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02
#include "../http/parser.hpp"
#include "../uri.hpp"
#include "../websocket_frame.hpp" // TODO: clean up
@@ -79,48 +79,48 @@ public:
#include <iostream>
namespace websocketpp {
namespace websocketpp_02 {
namespace processor {
class processor_base : boost::noncopyable {
public:
virtual ~processor_base() {}
// validate client handshake
// validate server handshake
// Given a list of HTTP headers determine if the values are sufficient
// to start a websocket session. If so begin constructing a response, if not throw a handshake
// to start a websocket session. If so begin constructing a response, if not throw a handshake
// exception.
// validate handshake request
virtual void validate_handshake(const http::parser::request& headers) const = 0;
virtual void handshake_response(const http::parser::request& request,http::parser::response& response) = 0;
// Extracts client origin from a handshake request
virtual std::string get_origin(const http::parser::request& request) const = 0;
// Extracts client uri from a handshake request
virtual uri_ptr get_uri(const http::parser::request& request) const = 0;
// consume bytes, throw on exception
virtual void consume(std::istream& s) = 0;
// is there a message ready to be dispatched?
virtual bool ready() const = 0;
virtual bool is_control() const = 0;
virtual message::data_ptr get_data_message() = 0;
virtual message::control_ptr get_control_message() = 0;
virtual void reset() = 0;
virtual uint64_t get_bytes_needed() const = 0;
// Get information about the message that is ready
//virtual frame::opcode::value get_opcode() const = 0;
//virtual utf8_string_ptr get_utf8_payload() const = 0;
//virtual binary_string_ptr get_binary_payload() const = 0;
//virtual close::status::value get_close_code() const = 0;
//virtual utf8_string get_close_reason() const = 0;
// TODO: prepare a frame
//virtual binary_string_ptr prepare_frame(frame::opcode::value opcode,
// bool mask,
@@ -132,17 +132,17 @@ public:
//virtual binary_string_ptr prepare_close_frame(close::status::value code,
// bool mask,
// const std::string& reason) = 0;
virtual void prepare_frame(message::data_ptr msg) = 0;
virtual void prepare_close_frame(message::data_ptr msg,
close::status::value code,
const std::string& reason) = 0;
};
typedef boost::shared_ptr<processor_base> ptr;
} // namespace processor
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKET_PROCESSOR_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* This Makefile was derived from a similar one included in the libjson project
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
*/
@@ -32,15 +32,15 @@
#include <stdint.h>
namespace websocketpp {
namespace websocketpp_02 {
class blank_rng {
public:
int32_t gen() {
throw "Random Number generation not supported";
}
};
}
#endif // BLANK_RNG_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,16 +22,16 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* This Makefile was derived from a similar one included in the libjson project
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
*/
#include "boost_rng.hpp"
using websocketpp::boost_rng;
using websocketpp_02::boost_rng;
boost_rng::boost_rng() : m_gen(m_rng,
boost_rng::boost_rng() : m_gen(m_rng,
boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)) {}
int32_t boost_rng::gen() {

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* This Makefile was derived from a similar one included in the libjson project
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
*/
@@ -38,7 +38,7 @@
#include <boost/random.hpp>
#include <boost/random/random_device.hpp>
namespace websocketpp {
namespace websocketpp_02 {
class boost_rng {
public:
boost_rng();

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_ROLE_CLIENT_HPP
@@ -50,9 +50,9 @@
using boost::asio::ip::tcp;
namespace websocketpp {
namespace websocketpp_02 {
namespace role {
template <class endpoint>
class client {
public:
@@ -62,19 +62,19 @@ public:
public:
typedef connection<connection_type> type;
typedef endpoint endpoint_type;
// client connections are friends with their respective client endpoint
friend class client<endpoint>;
// Valid always
int get_version() const {
return m_version;
}
std::string get_origin() const {
return m_origin;
}
// not sure when valid
std::string get_request_header(const std::string& key) const {
return m_request.header(key);
@@ -82,7 +82,7 @@ public:
std::string get_response_header(const std::string& key) const {
return m_response.header(key);
}
// Valid before connect is called
void add_request_header(const std::string& key, const std::string& value) {
m_request.add_header(key,value);
@@ -93,15 +93,15 @@ public:
void remove_request_header(const std::string& key) {
m_request.remove_header(key);
}
void add_subprotocol(const std::string& value) {
m_requested_subprotocols.push_back(value);
}
void set_origin(const std::string& value) {
m_origin = value;
}
// Information about the requested URI
// valid only after URIs are loaded
// TODO: check m_uri for NULLness
@@ -120,49 +120,49 @@ public:
std::string get_uri() const {
return m_uri->str();
}
int32_t rand() {
return m_endpoint.rand();
}
bool is_server() const {
return false;
}
// should this exist?
boost::asio::io_service& get_io_service() {
return m_endpoint.get_io_service();
}
protected:
connection(endpoint& e)
connection(endpoint& e)
: m_endpoint(e),
m_connection(static_cast< connection_type& >(*this)),
// TODO: version shouldn't be hardcoded
m_version(13) {}
void set_uri(uri_ptr u) {
m_uri = u;
}
void async_init() {
m_connection.m_processor = processor::ptr(new processor::hybi<connection_type>(m_connection));
m_connection.get_handler()->on_handshake_init(m_connection.shared_from_this());
write_request();
}
void write_request();
void handle_write_request(const boost::system::error_code& error);
void read_response();
void handle_read_response(const boost::system::error_code& error,
std::size_t bytes_transferred);
void log_open_result();
private:
endpoint& m_endpoint;
connection_type& m_connection;
int m_version;
uri_ptr m_uri;
std::string m_origin;
@@ -170,41 +170,41 @@ public:
std::vector<std::string> m_requested_extensions;
std::string m_subprotocol;
std::vector<std::string> m_extensions;
std::string m_handshake_key;
http::parser::request m_request;
http::parser::response m_response;
};
// types
typedef client<endpoint> type;
typedef endpoint endpoint_type;
typedef typename endpoint_traits<endpoint>::connection_type connection_type;
typedef typename endpoint_traits<endpoint>::connection_ptr connection_ptr;
typedef typename endpoint_traits<endpoint>::handler_ptr handler_ptr;
// handler interface callback class
class handler_interface {
public:
virtual ~handler_interface() {}
// Required
virtual void on_open(connection_ptr con) {}
virtual void on_close(connection_ptr con) {}
virtual void on_fail(connection_ptr con) {}
virtual void on_message(connection_ptr con,message::data_ptr) {}
// Optional
virtual void on_handshake_init(connection_ptr con) {}
virtual bool on_ping(connection_ptr con,std::string) {return true;}
virtual void on_pong(connection_ptr con,std::string) {}
virtual void on_pong_timeout(connection_ptr con,std::string) {}
};
client (boost::asio::io_service& m)
client (boost::asio::io_service& m)
: m_endpoint(static_cast< endpoint_type& >(*this)),
m_io_service(m),
m_gen(m_rng,
@@ -212,12 +212,12 @@ public:
(std::numeric_limits<int32_t>::min)(),
(std::numeric_limits<int32_t>::max)()
)) {}
connection_ptr get_connection(const std::string& u);
connection_ptr connect(const std::string& u);
connection_ptr connect(connection_ptr con);
void run(bool perpetual = false);
void end_perpetual();
void reset();
@@ -226,16 +226,16 @@ protected:
int32_t rand() {return m_gen();}
private:
void handle_connect(connection_ptr con, const boost::system::error_code& error);
endpoint_type& m_endpoint;
boost::asio::io_service& m_io_service;
boost::random::random_device m_rng;
boost::random::variate_generator<
boost::random::random_device&,
boost::random::uniform_int_distribution<>
> m_gen;
boost::shared_ptr<boost::asio::io_service::work> m_idle_worker;
};
@@ -253,41 +253,41 @@ private:
* immediately unless you have already called connect() at least once. To get around
* this either queue up all connections you want to make before calling run or call
* run with perpetual in another thread.
*
*
* Visibility: public
* State: Valid from IDLE, an exception is thrown otherwise
* Concurrency: callable from any thread
*
* @param perpetual whether or not to run the endpoint in perpetual mode
* @exception websocketpp::exception with code error::INVALID_STATE if called from a state other than IDLE
* @exception websocketpp_02::exception with code error::INVALID_STATE if called from a state other than IDLE
*/
template <class endpoint>
void client<endpoint>::run(bool perpetual) {
{
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
if (m_endpoint.m_state != endpoint::IDLE) {
throw exception("client::run called from invalid state",error::INVALID_STATE);
}
if (perpetual) {
m_idle_worker = boost::shared_ptr<boost::asio::io_service::work>(
new boost::asio::io_service::work(m_io_service)
);
}
m_endpoint.m_state = endpoint::RUNNING;
}
// TODO: preliminary support for multi-threaded clients. Finish external
// interface once better tested
size_t num_threads = 1;
if (num_threads == 1) {
m_io_service.run();
} else if (num_threads > 1 && num_threads <= MAX_THREAD_POOL_SIZE) {
std::vector< boost::shared_ptr<boost::thread> > threads;
for (std::size_t i = 0; i < num_threads; ++i) {
boost::shared_ptr<boost::thread> thread(
new boost::thread(boost::bind(
@@ -297,24 +297,24 @@ void client<endpoint>::run(bool perpetual) {
);
threads.push_back(thread);
}
for (std::size_t i = 0; i < threads.size(); ++i) {
threads[i]->join();
}
} else {
throw exception("listen called with invalid num_threads value");
}
m_endpoint.m_state = endpoint::STOPPED;
}
/// End the idle work loop that keeps the io_service active
/**
* Calling end_perpetual on a client endpoint that was started in perpetual mode (via
* run(true), will stop the idle work object that prevents the run method from
* run(true), will stop the idle work object that prevents the run method from
* returning even when there is no work for it to do. Use if you want to gracefully
* stop the endpoint. Use stop() to forcibly stop the endpoint.
*
*
* Visibility: public
* State: Valid from RUNNING, ignored otherwise
* Concurrency: callable from any thread
@@ -332,7 +332,7 @@ void client<endpoint>::end_perpetual() {
* running out of work. reset() should not be called while the endpoint is running.
* Use stop() and/or end_perpetual() first and then reset once one of those methods
* has fully stopped the endpoint.
*
*
* Visibility: public
* State: Valid from STOPPED, an exception is thrown otherwise
* Concurrency: callable from any thread
@@ -340,22 +340,22 @@ void client<endpoint>::end_perpetual() {
template <class endpoint>
void client<endpoint>::reset() {
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
if (m_endpoint.m_state != endpoint::STOPPED) {
throw exception("client::reset called from invalid state",error::INVALID_STATE);
}
m_io_service.reset();
m_endpoint.m_state = endpoint::IDLE;
}
/// Returns a new connection
/// Returns a new connection
/**
* Creates and returns a pointer to a new connection to the given URI suitable for passing
* to connect(). This method allows applying connection specific settings before
* to connect(). This method allows applying connection specific settings before
* performing the connection.
*
*
* Visibility: public
* State: Valid from IDLE or RUNNING, an exception is thrown otherwise
* Concurrency: callable from any thread
@@ -368,31 +368,31 @@ typename endpoint_traits<endpoint>::connection_ptr
client<endpoint>::get_connection(const std::string& u) {
try {
uri_ptr location(new uri(u));
if (location->get_secure() && !m_endpoint.is_secure()) {
throw websocketpp::exception("Endpoint doesn't support secure connections.",
websocketpp::error::ENDPOINT_UNSECURE);
throw websocketpp_02::exception("Endpoint doesn't support secure connections.",
websocketpp_02::error::ENDPOINT_UNSECURE);
}
connection_ptr con = m_endpoint.create_connection();
if (!con) {
throw websocketpp::exception("get_connection called from invalid state",
websocketpp::error::INVALID_STATE);
throw websocketpp_02::exception("get_connection called from invalid state",
websocketpp_02::error::INVALID_STATE);
}
con->set_uri(location);
return con;
} catch (uri_exception& e) {
throw websocketpp::exception(e.what(),websocketpp::error::INVALID_URI);
throw websocketpp_02::exception(e.what(),websocketpp_02::error::INVALID_URI);
}
}
/// Begin the connect process for the given connection.
/**
* Initiates the async connect request for connection con.
*
*
* Visibility: public
* State: Valid from IDLE or RUNNING, an exception is thrown otherwise
* Concurrency: callable from any thread
@@ -404,13 +404,13 @@ template <class endpoint>
typename endpoint_traits<endpoint>::connection_ptr
client<endpoint>::connect(connection_ptr con) {
tcp::resolver resolver(m_io_service);
std::stringstream p;
p << con->get_port();
tcp::resolver::query query(con->get_host(),p.str());
tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::async_connect(
con->get_raw_socket(),
iterator,
@@ -420,8 +420,8 @@ client<endpoint>::connect(connection_ptr con) {
con,
boost::asio::placeholders::error
)
);
);
return con;
}
@@ -433,18 +433,18 @@ client<endpoint>::connect(const std::string& u) {
}
template <class endpoint>
void client<endpoint>::handle_connect(connection_ptr con,
void client<endpoint>::handle_connect(connection_ptr con,
const boost::system::error_code& error)
{
if (!error) {
m_endpoint.m_alog->at(log::alevel::CONNECT)
<< "Successful connection" << log::endl;
con->start();
} else {
con->m_fail_code = fail::status::SYSTEM;
con->m_fail_system = error;
if (error == boost::system::errc::connection_refused) {
con->m_fail_reason = "Connection refused";
} else if (error == boost::system::errc::operation_canceled) {
@@ -458,11 +458,11 @@ void client<endpoint>::handle_connect(connection_ptr con,
} else {
con->m_fail_reason = "Unknown";
}
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "An error occurred while establishing a connection: "
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "An error occurred while establishing a connection: "
<< error << " (" << con->m_fail_reason << ")" << log::endl;
con->terminate(false);
}
}
@@ -474,60 +474,60 @@ template <class connection_type>
void client<endpoint>::connection<connection_type>::write_request() {
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
// async write to handle_write
m_request.set_method("GET");
m_request.set_uri(m_uri->get_resource());
m_request.set_version("HTTP/1.1");
m_request.add_header("Upgrade","websocket");
m_request.add_header("Connection","Upgrade");
m_request.replace_header("Sec-WebSocket-Version","13");
m_request.replace_header("Host",m_uri->get_host_port());
if (m_origin != "") {
m_request.replace_header("Origin",m_origin);
}
if (m_requested_subprotocols.size() > 0) {
std::string vals;
std::string sep = "";
std::vector<std::string>::iterator it;
for (it = m_requested_subprotocols.begin(); it != m_requested_subprotocols.end(); ++it) {
vals += sep + *it;
sep = ",";
}
m_request.replace_header("Sec-WebSocket-Protocol",vals);
}
// Generate client key
int32_t raw_key[4];
for (int i = 0; i < 4; i++) {
raw_key[i] = this->rand();
}
m_handshake_key = base64_encode(reinterpret_cast<unsigned char const*>(raw_key), 16);
m_request.replace_header("Sec-WebSocket-Key",m_handshake_key);
// Unless the user has overridden the user agent, send generic WS++
if (m_request.header("User-Agent") == "") {
m_request.replace_header("User-Agent",USER_AGENT);
}
// TODO: generating this raw request involves way too much copying in cases
// without string/vector move semantics.
shared_const_buffer buffer(m_request.raw());
//std::string raw = m_request.raw();
//m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << raw << log::endl;
boost::asio::async_write(
m_connection.get_socket(),
//boost::asio::buffer(raw),
@@ -547,14 +547,14 @@ void client<endpoint>::connection<connection_type>::handle_write_request(
{
if (error) {
// TODO: detached state?
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error writing WebSocket request. code: "
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error writing WebSocket request. code: "
<< error << log::endl;
m_connection.terminate(false);
return;
}
read_response();
}
@@ -580,50 +580,50 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
const boost::system::error_code& error, std::size_t bytes_transferred)
{
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
// detached check?
if (error) {
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error reading HTTP request. code: " << error << log::endl;
m_connection.terminate(false);
return;
}
try {
std::istream request(&m_connection.buffer());
if (!m_response.parse_complete(request)) {
// not a valid HTTP response
// TODO: this should be a client error
throw http::exception("Could not parse server response.",
http::status_code::BAD_REQUEST);
}
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << m_response.raw()
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << m_response.raw()
<< log::endl;
// error checking
if (m_response.get_status_code() != http::status_code::SWITCHING_PROTOCOLS) {
throw http::exception("Server failed to upgrade connection.",
m_response.get_status_code(),
m_response.get_status_msg());
}
std::string h = m_response.header("Upgrade");
if (!boost::ifind_first(h,"websocket")) {
throw http::exception("Token `websocket` missing from Upgrade header.",
m_response.get_status_code(),
m_response.get_status_msg());
}
h = m_response.header("Connection");
if (!boost::ifind_first(h,"upgrade")) {
throw http::exception("Token `upgrade` missing from Connection header.",
m_response.get_status_code(),
m_response.get_status_msg());
}
h = m_response.header("Sec-WebSocket-Accept");
if (h == "") {
throw http::exception("Required Sec-WebSocket-Accept header is missing.",
@@ -632,26 +632,26 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
} else {
std::string server_key = m_handshake_key;
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
uint32_t message_digest[5];
sha.Reset();
sha << server_key.c_str();
if (!sha.Result(message_digest)) {
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error computing handshake sha1 hash." << log::endl;
// TODO: close behavior
return;
}
// convert sha1 hash bytes to network byte order because this sha1
// library works on ints rather than bytes
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
server_key = base64_encode(
reinterpret_cast<const unsigned char*>(message_digest),20);
if (server_key != h) {
@@ -661,13 +661,13 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
return;
}
}
log_open_result();
m_connection.m_state = session::state::OPEN;
m_connection.get_handler()->on_open(m_connection.shared_from_this());
get_io_service().post(
m_connection.m_strand.wrap(boost::bind(
&connection_type::handle_read_frame,
@@ -675,17 +675,17 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
boost::system::error_code()
))
);
//m_connection.handle_read_frame(boost::system::error_code());
} catch (const http::exception& e) {
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error processing server handshake. Server HTTP response: "
<< e.m_error_msg << " (" << e.m_error_code
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error processing server handshake. Server HTTP response: "
<< e.m_error_msg << " (" << e.m_error_code
<< ") Local error: " << e.what() << log::endl;
return;
}
// start session loop
}
@@ -694,18 +694,18 @@ template <class connection_type>
void client<endpoint>::connection<connection_type>::log_open_result() {
std::stringstream version;
version << "v" << m_version << " ";
m_endpoint.m_alog->at(log::alevel::CONNECT)
<< (m_version == -1 ? "HTTP" : "WebSocket") << " Connection "
<< m_connection.get_raw_socket().remote_endpoint() << " "
<< (m_version == -1 ? "" : version.str())
<< (get_request_header("Server") == "" ? "NULL" : get_request_header("Server"))
<< " " << m_uri->get_resource() << " " << m_response.get_status_code()
<< (get_request_header("Server") == "" ? "NULL" : get_request_header("Server"))
<< " " << m_uri->get_resource() << " " << m_response.get_status_code()
<< log::endl;
}
} // namespace role
} // namespace websocketpp
} // namespace websocketpp_02
#ifdef _MSC_VER
# pragma warning(pop)

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_ROLE_SERVER_HPP
@@ -53,7 +53,7 @@
# pragma warning(disable:4355)
#endif
namespace websocketpp {
namespace websocketpp_02 {
typedef boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> bufIterator;
@@ -96,7 +96,7 @@ static inline std::pair<bufIterator, bool> match_header(boost::shared_ptr<std::s
// Forward declarations
template <typename T> struct endpoint_traits;
namespace role {
template <class endpoint>
@@ -108,7 +108,7 @@ public:
public:
typedef connection<connection_type> type;
typedef endpoint endpoint_type;
// Valid always
int get_version() const {
return m_version;
@@ -119,7 +119,7 @@ public:
std::string get_origin() const {
return m_origin;
}
// Information about the requested URI
// valid only after URIs are loaded
// TODO: check m_uri for NULLness
@@ -135,7 +135,7 @@ public:
uint16_t get_port() const {
return m_uri->get_port();
}
// Valid for CONNECTING state
void add_response_header(const std::string& key, const std::string& value) {
m_response.add_header(key,value);
@@ -146,7 +146,7 @@ public:
void remove_response_header(const std::string& key) {
m_response.remove_header(key);
}
const std::vector<std::string>& get_subprotocols() const {
return m_requested_subprotocols;
}
@@ -155,18 +155,18 @@ public:
}
void select_subprotocol(const std::string& value);
void select_extension(const std::string& value);
// Valid if get_version() returns -1 (ie this is an http connection)
void set_body(const std::string& value);
int32_t rand() {
return 0;
}
bool is_server() const {
return true;
}
// should this exist?
boost::asio::io_service& get_io_service() {
return m_endpoint.get_io_service();
@@ -177,7 +177,7 @@ public:
m_connection(static_cast< connection_type& >(*this)),
m_version(-1),
m_uri() {}
// initializes the websocket connection
void async_init();
void handle_read_request(boost::shared_ptr<std::string>, const boost::system::error_code& error,
@@ -186,12 +186,12 @@ public:
std::size_t bytes_transferred);
void write_response();
void handle_write_response(const boost::system::error_code& error);
void log_open_result();
private:
endpoint& m_endpoint;
connection_type& m_connection;
int m_version;
uri_ptr m_uri;
std::string m_origin;
@@ -199,33 +199,33 @@ public:
std::vector<std::string> m_requested_extensions;
std::string m_subprotocol;
std::vector<std::string> m_extensions;
http::parser::request m_request;
http::parser::response m_response;
blank_rng m_rng;
};
// types
typedef server<endpoint> type;
typedef endpoint endpoint_type;
typedef typename endpoint_traits<endpoint>::connection_ptr connection_ptr;
typedef typename endpoint_traits<endpoint>::handler_ptr handler_ptr;
// handler interface callback base class
class handler_interface {
public:
virtual ~handler_interface() {}
virtual void on_handshake_init(connection_ptr con) {}
virtual void validate(connection_ptr con) {}
virtual void on_open(connection_ptr con) {}
virtual void on_close(connection_ptr con) {}
virtual void on_fail(connection_ptr con) {}
virtual void on_message(connection_ptr con,message::data_ptr) {}
virtual bool on_ping(connection_ptr con,std::string) {return true;}
virtual void on_pong(connection_ptr con,std::string) {}
virtual void on_pong_timeout(connection_ptr con,std::string) {}
@@ -233,8 +233,8 @@ public:
virtual void on_send_empty(connection_ptr con) {}
};
server(boost::asio::io_service& m)
server(boost::asio::io_service& m)
: m_endpoint(static_cast< endpoint_type& >(*this)),
m_io_service(m),
// the only way to set an endpoint address family appears to be using
@@ -243,15 +243,15 @@ public:
m_acceptor(m),
m_state(IDLE),
m_timer(m,boost::posix_time::seconds(0)) {}
void start_listen(uint16_t port, size_t num_threads = 1);
void start_listen(const boost::asio::ip::tcp::endpoint& e, size_t num_threads = 1);
// uses internal resolver
void start_listen(const std::string &host, const std::string &service, size_t num_threads = 1);
template <typename InternetProtocol>
template <typename InternetProtocol>
void start_listen(const InternetProtocol &internet_protocol, uint16_t port, size_t num_threads = 1) {
m_endpoint.m_alog->at(log::alevel::DEVEL)
m_endpoint.m_alog->at(log::alevel::DEVEL)
<< "role::server listening on port " << port << log::endl;
boost::asio::ip::tcp::endpoint e(internet_protocol, port);
start_listen(e,num_threads);
@@ -272,7 +272,7 @@ public:
start_listen(host,service,num_threads>1 ? num_threads : 0);
if(num_threads > 1) stop_listen(true);
}
template <typename InternetProtocol>
template <typename InternetProtocol>
void listen(const InternetProtocol &internet_protocol, uint16_t port, size_t num_threads = 1) {
start_listen(internet_protocol,port,num_threads>1 ? num_threads : 0);
if(num_threads > 1) stop_listen(true);
@@ -289,21 +289,21 @@ private:
STOPPING = 2,
STOPPED = 3
};
// start_accept creates a new connection and begins an async_accept on it
void start_accept();
// handle_accept will begin the connection's read/write loop and then reset
// the server to accept a new connection. Errors returned by async_accept
// are logged and ingored.
void handle_accept(connection_ptr con,
void handle_accept(connection_ptr con,
const boost::system::error_code& error);
endpoint_type& m_endpoint;
boost::asio::io_service& m_io_service;
boost::asio::ip::tcp::acceptor m_acceptor;
state m_state;
boost::asio::deadline_timer m_timer;
std::vector< boost::shared_ptr<std::thread> > m_listening_threads;
@@ -313,20 +313,20 @@ template <class endpoint>
void server<endpoint>::start_listen(const boost::asio::ip::tcp::endpoint& e,size_t num_threads) {
{
boost::unique_lock<boost::recursive_mutex> lock(m_endpoint.m_lock);
if (m_state != IDLE) {
throw exception("listen called from invalid state.");
}
m_acceptor.open(e.protocol());
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true));
m_acceptor.bind(e);
m_acceptor.listen();
this->start_accept();
}
if (num_threads > MAX_THREAD_POOL_SIZE) {
if (num_threads > MAX_THREAD_POOL_SIZE) {
throw exception("listen called with invalid num_threads value");
}
@@ -360,14 +360,14 @@ template <class endpoint>
void server<endpoint>::stop_listen(bool join) {
{
boost::unique_lock<boost::recursive_mutex> lock(m_endpoint.m_lock);
if (m_state != LISTENING) {
throw exception("stop_listen called from invalid state");
}
m_acceptor.close();
}
if(join) {
for (std::size_t i = 0; i < m_listening_threads.size(); ++i) {
m_listening_threads[i]->join();
@@ -400,17 +400,17 @@ void server<endpoint>::start_listen(const std::string &host, const std::string &
template <class endpoint>
void server<endpoint>::start_accept() {
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
connection_ptr con = m_endpoint.create_connection();
if (con == connection_ptr()) {
// the endpoint is no longer capable of accepting new connections.
m_endpoint.m_alog->at(log::alevel::CONNECT)
<< "Connection refused because endpoint is out of resources or closing."
m_endpoint.m_alog->at(log::alevel::CONNECT)
<< "Connection refused because endpoint is out of resources or closing."
<< log::endl;
return;
}
m_acceptor.async_accept(
con->get_native_socket (),
boost::bind(
@@ -426,7 +426,7 @@ void server<endpoint>::start_accept() {
// the server to accept a new connection. Errors returned by async_accept
// are logged and ingored.
template <class endpoint>
void server<endpoint>::handle_accept(connection_ptr con,
void server<endpoint>::handle_accept(connection_ptr con,
const boost::system::error_code& error)
{
bool delay = false;
@@ -475,7 +475,7 @@ void server<endpoint>::handle_accept(connection_ptr con,
else
this->start_accept();
}
// server<endpoint>::connection<connnection_type> Implimentation
template <class endpoint>
@@ -484,17 +484,17 @@ void server<endpoint>::connection<connection_type>::select_subprotocol(
const std::string& value)
{
// TODO: should this be locked?
std::vector<std::string>::iterator it;
it = std::find(m_requested_subprotocols.begin(),
m_requested_subprotocols.end(),
value);
if (value != "" && it == m_requested_subprotocols.end()) {
throw std::invalid_argument("Attempted to choose a subprotocol not proposed by the client");
}
m_subprotocol = value;
}
@@ -504,21 +504,21 @@ void server<endpoint>::connection<connection_type>::select_extension(
const std::string& value)
{
// TODO: should this be locked?
if (value == "") {
return;
}
std::vector<std::string>::iterator it;
it = std::find(m_requested_extensions.begin(),
m_requested_extensions.end(),
value);
if (it == m_requested_extensions.end()) {
throw std::invalid_argument("Attempted to choose an extension not proposed by the client");
}
m_extensions.push_back(value);
}
@@ -529,15 +529,15 @@ void server<endpoint>::connection<connection_type>::set_body(
const std::string& value)
{
// TODO: should this be locked?
if (m_connection.m_version != -1) {
// TODO: throw exception
throw std::invalid_argument("set_body called from invalid state");
}
m_response.set_body(value);
}
/// initiates an async read for an HTTP header
/**
* Thread Safety: locks connection
@@ -546,9 +546,9 @@ template <class endpoint>
template <class connection_type>
void server<endpoint>::connection<connection_type>::async_init() {
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
m_connection.get_handler()->on_handshake_init(m_connection.shared_from_this());
// TODO: make this value configurable
m_connection.register_timeout(5000,fail::status::TIMEOUT_WS,
"Timeout on WebSocket handshake");
@@ -583,17 +583,17 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
{
if (error) {
// log error
m_endpoint.m_elog->at(log::elevel::RERROR)
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error reading HTTP request. code: " << error << log::endl;
m_connection.terminate(false);
return;
}
m_connection.buffer().consume(header->size());
try {
std::istringstream request(*header);
if (!m_request.parse_complete(request)) {
// not a valid HTTP request/response
if (m_request.method().find("<policy-file-request/>") != std::string::npos)
@@ -620,15 +620,15 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
}
throw http::exception("Received invalid HTTP Request",http::status_code::BAD_REQUEST);
}
// TODO: is there a way to short circuit this or something?
// TODO: is there a way to short circuit this or something?
// This is often useful but slow to generate.
//m_endpoint.m_alog.at(log::alevel::DEBUG_HANDSHAKE) << m_request.raw() << log::endl;
std::string h = m_request.header("Upgrade");
if (boost::ifind_first(h,"websocket")) {
// Version is stored in the Sec-WebSocket-Version header for all
// versions after draft Hybi 00/Hixie 76. The absense of a version
// Version is stored in the Sec-WebSocket-Version header for all
// versions after draft Hybi 00/Hixie 76. The absense of a version
// header is assumed to mean Hybi 00.
h = m_request.header("Sec-WebSocket-Version");
if (h == "") {
@@ -639,45 +639,45 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
throw(http::exception("Unable to determine connection version",http::status_code::BAD_REQUEST));
}
}
// Choose an appropriate websocket processor based on the version
if (m_version == 0) {
m_connection.m_processor = processor::ptr(
new processor::hybi_legacy<connection_type>(m_connection)
);
// Hybi legacy requires some extra out of band bookkeeping that
// Hybi legacy requires some extra out of band bookkeeping that
// future versions wont. We need to pull off an additional eight
// bytes after the /r/n/r/n and store them somewhere that the
// processor can find them.
char foo[8];
request.read(foo,8);
if (request.gcount() != 8) {
size_t left = 8 - static_cast<size_t>(request.gcount());
// This likely occurs because the full key3 wasn't included
// in the asio read. It is likely that the extra bytes are
// actually on the wire and another asio read would get them
// Fixing this will require a way of restarting the
// Fixing this will require a way of restarting the
// handshake read and storing the existing bytes until that
// comes back. Issue #101
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Short Key 3: " << zsutil::to_hex(std::string(foo))
<< " bytes missing: " << left
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Short Key 3: " << zsutil::to_hex(std::string(foo))
<< " bytes missing: " << left
<< " eofbit: " << (request.eof() ? "true" : "false")
<< " failbit: " << (request.fail() ? "true" : "false")
<< " badbit: " << (request.bad() ? "true" : "false")
<< " goodbit: " << (request.good() ? "true" : "false")
<< log::endl;
throw http::exception("Full Key3 not found in first chop",
http::status_code::INTERNAL_SERVER_ERROR);
/*m_request.add_header("Sec-WebSocket-Key3",std::string(foo));
boost::asio::async_read(
m_connection.get_socket(),
m_connection.buffer(),
@@ -697,16 +697,16 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
new processor::hybi<connection_type>(m_connection)
);
} else {
// version does not match any processor we have avaliable. Send
// version does not match any processor we have avaliable. Send
// an HTTP error and return the versions we do support in a the
// appropriate response header.
m_response.add_header("Sec-WebSocket-Version","13, 8, 7");
throw(http::exception("Unsupported WebSocket version",http::status_code::BAD_REQUEST));
}
m_connection.m_processor->validate_handshake(m_request);
// Extract subprotocols
std::string subprotocols = m_request.header("Sec-WebSocket-Protocol");
if(subprotocols.length() > 0) {
@@ -720,24 +720,24 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
}
}
}
m_origin = m_connection.m_processor->get_origin(m_request);
m_uri = m_connection.m_processor->get_uri(m_request);
m_endpoint.get_handler()->validate(m_connection.shared_from_this());
m_response.set_status(http::status_code::SWITCHING_PROTOCOLS);
} else {
// should there be a more encapsulated http processor here?
m_origin = m_request.header("Origin");
// Set URI
std::string h = m_request.header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
if (last_colon == std::string::npos ||
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
// TODO: this makes the assumption that WS and HTTP
@@ -749,7 +749,7 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
h.substr(last_colon+1),
m_request.uri()));
}
// continue as HTTP?
if (m_endpoint.get_handler()->http(m_connection.shared_from_this()))
m_response.set_status(http::status_code::OK);
@@ -765,7 +765,7 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
m_response.set_status(http::status_code::BAD_REQUEST);
}
write_response();
}
@@ -776,48 +776,48 @@ void server<endpoint>::connection<connection_type>::handle_short_key3 (
{
if (error) {
// log error
m_endpoint.m_elog->at(log::elevel::RERROR)
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Error reading HTTP request. code: " << error << log::endl;
m_connection.terminate(false);
return;
}
try {
std::istream request(&m_connection.buffer());
std::string foo = m_request.header("Sec-WebSocket-Key3");
size_t left = 8-foo.size();
if (left == 0) {
// ?????
throw http::exception("handle_short_key3 called without short key",
http::status_code::INTERNAL_SERVER_ERROR);
}
char foo2[9];
request.get(foo2,left);
if (request.gcount() != left) {
// ?????
throw http::exception("Full Key3 not found",
http::status_code::INTERNAL_SERVER_ERROR);
}
m_endpoint.m_elog->at(log::elevel::RERROR)
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Recovered from Short Key 3: " << left << log::endl;
foo.append(std::string(foo2));
m_request.replace_header("Sec-WebSocket-Key3",foo2);
m_connection.m_processor->validate_handshake(m_request);
m_origin = m_connection.m_processor->get_origin(m_request);
m_uri = m_connection.m_processor->get_uri(m_request);
m_endpoint.get_handler()->validate(m_connection.shared_from_this());
m_response.set_status(http::status_code::SWITCHING_PROTOCOLS);
} catch (const http::exception& e) {
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
@@ -828,7 +828,7 @@ void server<endpoint>::connection<connection_type>::handle_short_key3 (
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
m_response.set_status(http::status_code::BAD_REQUEST);
}
write_response();
}
@@ -836,34 +836,34 @@ template <class endpoint>
template <class connection_type>
void server<endpoint>::connection<connection_type>::write_response() {
bool ws_response = true;
m_response.set_version("HTTP/1.1");
if (m_response.get_status_code() == http::status_code::SWITCHING_PROTOCOLS) {
// websocket response
m_connection.m_processor->handshake_response(m_request,m_response);
if (m_subprotocol != "") {
m_response.replace_header("Sec-WebSocket-Protocol",m_subprotocol);
}
// TODO: return negotiated extensions
} else {
// TODO: HTTP response
ws_response = false;
}
m_response.replace_header("Server",USER_AGENT);
std::string raw = m_response.raw();
// Hack for legacy HyBi
if (ws_response && m_version == 0) {
raw += boost::dynamic_pointer_cast<processor::hybi_legacy<connection_type> >(m_connection.m_processor)->get_key3();
}
shared_const_buffer buffer(raw);
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << raw << log::endl;
boost::asio::async_write(
@@ -884,37 +884,37 @@ void server<endpoint>::connection<connection_type>::handle_write_response(
const boost::system::error_code& error)
{
if (error) {
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Network error writing handshake respons. code: " << error
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Network error writing handshake respons. code: " << error
<< log::endl;
m_connection.terminate(false);
return;
}
if (m_response.get_status_code() != http::status_code::SWITCHING_PROTOCOLS) {
if (m_version == -1) {
// if this was not a websocket connection, we have written
// if this was not a websocket connection, we have written
// the expected response and the connection can be closed.
} else {
// this was a websocket connection that ended in an error
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Handshake ended with HTTP error: "
<< m_response.get_status_code() << " "
m_endpoint.m_elog->at(log::elevel::RERROR)
<< "Handshake ended with HTTP error: "
<< m_response.get_status_code() << " "
<< m_response.get_status_msg() << log::endl;
}
m_connection.terminate(true);
return;
}
m_connection.cancel_timeout();
log_open_result();
m_connection.m_state = session::state::OPEN;
m_connection.get_handler()->on_open(m_connection.shared_from_this());
get_io_service().post(
m_connection.m_strand.wrap(boost::bind(
&connection_type::handle_read_frame,
@@ -922,7 +922,7 @@ void server<endpoint>::connection<connection_type>::handle_write_response(
boost::system::error_code()
))
);
//m_connection.handle_read_frame(boost::system::error_code());
}
@@ -931,33 +931,33 @@ template <class connection_type>
void server<endpoint>::connection<connection_type>::log_open_result() {
std::stringstream version;
version << "v" << m_version << " ";
std::string remote;
boost::system::error_code ec; // FIXME: proxy
boost::asio::ip::tcp::endpoint ep = m_connection.get_native_socket().remote_endpoint(ec);
if (ec) {
m_endpoint.m_elog->at(log::elevel::WARN)
m_endpoint.m_elog->at(log::elevel::WARN)
<< "Error getting remote endpoint. code: " << ec << log::endl;
}
m_endpoint.m_alog->at(log::alevel::CONNECT)
m_endpoint.m_alog->at(log::alevel::CONNECT)
<< (m_version == -1 ? "HTTP" : "WebSocket") << " Connection ";
if (ec) {
m_endpoint.m_alog->at(log::alevel::CONNECT) << "Unknown";
} else {
m_endpoint.m_alog->at(log::alevel::CONNECT) << ep;
}
m_endpoint.m_alog->at(log::alevel::CONNECT) << " "
<< (m_version == -1 ? "" : version.str())
<< (get_request_header("User-Agent") == "" ? "NULL" : get_request_header("User-Agent"))
<< " " << (m_uri ? m_uri->get_resource() : "uri is NULL") << " "
<< (get_request_header("User-Agent") == "" ? "NULL" : get_request_header("User-Agent"))
<< " " << (m_uri ? m_uri->get_resource() : "uri is NULL") << " "
<< m_response.get_status_code() << log::endl;
}
} // namespace role
} // namespace websocketpp
} // namespace role
} // namespace websocketpp_02
#ifdef _MSC_VER
# pragma warning(pop)

View File

@@ -37,10 +37,10 @@
*
*/
namespace websocketpp
namespace websocketpp_02
{
/*
/*
* SHA1
*
* Description:
@@ -60,7 +60,7 @@ SHA1::SHA1()
Reset();
}
/*
/*
* ~SHA1
*
* Description:
@@ -80,7 +80,7 @@ SHA1::~SHA1()
// The destructor does nothing
}
/*
/*
* Reset
*
* Description:
@@ -112,7 +112,7 @@ void SHA1::Reset()
Corrupted = false;
}
/*
/*
* Result
*
* Description:
@@ -153,7 +153,7 @@ bool SHA1::Result(unsigned *message_digest_array)
return true;
}
/*
/*
* Input
*
* Description:
@@ -210,7 +210,7 @@ void SHA1::Input( const unsigned char *message_array,
}
}
/*
/*
* Input
*
* Description:
@@ -236,7 +236,7 @@ void SHA1::Input( const char *message_array,
Input((unsigned char *) message_array, length);
}
/*
/*
* Input
*
* Description:
@@ -257,7 +257,7 @@ void SHA1::Input(unsigned char message_element)
Input(&message_element, 1);
}
/*
/*
* Input
*
* Description:
@@ -278,7 +278,7 @@ void SHA1::Input(char message_element)
Input((unsigned char *) &message_element, 1);
}
/*
/*
* operator<<
*
* Description:
@@ -309,7 +309,7 @@ SHA1& SHA1::operator<<(const char *message_array)
return *this;
}
/*
/*
* operator<<
*
* Description:
@@ -340,7 +340,7 @@ SHA1& SHA1::operator<<(const unsigned char *message_array)
return *this;
}
/*
/*
* operator<<
*
* Description:
@@ -364,7 +364,7 @@ SHA1& SHA1::operator<<(const char message_element)
return *this;
}
/*
/*
* operator<<
*
* Description:
@@ -388,7 +388,7 @@ SHA1& SHA1::operator<<(const unsigned char message_element)
return *this;
}
/*
/*
* ProcessMessageBlock
*
* Description:
@@ -496,7 +496,7 @@ void SHA1::ProcessMessageBlock()
Message_Block_Index = 0;
}
/*
/*
* PadMessage
*
* Description:
@@ -565,7 +565,7 @@ void SHA1::PadMessage()
}
/*
/*
* CircularShift
*
* Description:

View File

@@ -24,7 +24,7 @@
#ifndef _SHA1_H_
#define _SHA1_H_
namespace websocketpp {
namespace websocketpp_02 {
class SHA1
{
@@ -84,9 +84,9 @@ class SHA1
bool Computed; // Is the digest computed?
bool Corrupted; // Is the message digest corruped?
};
} // namespace websocketpp
} // namespace websocketpp_02
#endif // _SHA1_H_

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef SHARED_CONST_BUFFER_HPP
@@ -35,7 +35,7 @@
#include <string>
#include <vector>
namespace websocketpp {
namespace websocketpp_02 {
class shared_const_buffer {
public:
@@ -51,6 +51,6 @@ private:
boost::asio::const_buffer m_buffer;
};
} // namespace websocketpp
} // namespace websocketpp_02
#endif // SHARED_CONST_BUFFER_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_SOCKET_AUTOTLS_HPP
@@ -34,7 +34,7 @@
// Note that AutoSocket.h must be included before this file
namespace websocketpp {
namespace websocketpp_02 {
namespace socket {
template <typename endpoint_type>
@@ -43,7 +43,7 @@ public:
typedef autotls<endpoint_type> type;
typedef AutoSocket autotls_socket;
typedef boost::shared_ptr<autotls_socket> autotls_socket_ptr;
// should be private friended
boost::asio::io_service& get_io_service() {
return m_io_service;
@@ -70,7 +70,7 @@ public:
virtual bool plain_only() = 0;
virtual bool secure_only() = 0;
};
// Connection specific details
template <typename connection_type>
class connection {
@@ -79,11 +79,11 @@ public:
autotls_socket::lowest_layer_type& get_raw_socket() {
return m_socket_ptr->lowest_layer();
}
autotls_socket& get_socket() {
return *m_socket_ptr;
}
bool is_secure() {
return m_socket_ptr->isSecure();
}
@@ -97,7 +97,7 @@ public:
connection(autotls<endpoint_type>& e)
: m_endpoint(e)
, m_connection(static_cast< connection_type& >(*this)) {}
void init() {
boost::asio::ssl::context& ssl_context (
m_connection.get_handler()->get_ssl_context());
@@ -106,17 +106,17 @@ public:
m_endpoint.get_io_service(), ssl_context, m_connection.get_handler()->secure_only(),
m_connection.get_handler()->plain_only()));
}
void async_init(boost::function<void(const boost::system::error_code&)> callback)
{
m_connection.get_handler()->on_tcp_init();
// wait for TLS handshake
// TODO: configurable value
m_connection.register_timeout(5000,
fail::status::TIMEOUT_TLS,
"Timeout on TLS handshake");
m_socket_ptr->async_handshake(
m_endpoint.get_handshake_type(),
std::bind(
@@ -127,17 +127,17 @@ public:
)
);
}
void handle_init(socket_init_callback callback,const boost::system::error_code& error) {
m_connection.cancel_timeout();
callback(error);
}
// note, this function for some reason shouldn't/doesn't need to be
// note, this function for some reason shouldn't/doesn't need to be
// called for plain HTTP connections. not sure why.
bool shutdown() {
boost::system::error_code ignored_ec;
m_socket_ptr->async_shutdown( // Don't block on connection shutdown DJS
std::bind(
&autotls<endpoint_type>::handle_shutdown,
@@ -145,7 +145,7 @@ public:
beast::asio::placeholders::error
)
);
if (ignored_ec) {
return false;
} else {
@@ -166,8 +166,8 @@ protected:
private:
boost::asio::io_service& m_io_service;
};
} // namespace socket
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKETPP_SOCKET_AUTOTLS_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#error Use Auto TLS only
@@ -43,7 +43,7 @@
# pragma warning(disable:4355)
#endif
namespace websocketpp {
namespace websocketpp_02 {
namespace socket {
template <typename endpoint_type>
@@ -52,19 +52,19 @@ public:
boost::asio::io_service& get_io_service() {
return m_io_service;
}
bool is_secure() {
return false;
}
// hooks that this policy adds to handlers of connections that use it
class handler_interface {
public:
virtual ~handler_interface() {}
virtual void on_tcp_init() {};
};
// Connection specific details
template <typename connection_type>
class connection {
@@ -73,11 +73,11 @@ public:
boost::asio::ip::tcp::socket& get_raw_socket() {
return m_socket;
}
boost::asio::ip::tcp::socket& get_socket() {
return m_socket;
}
bool is_secure() {
return false;
}
@@ -85,25 +85,25 @@ public:
connection(plain<endpoint_type>& e)
: m_socket(e.get_io_service())
, m_connection(static_cast< connection_type& >(*this)) {}
void init() {
}
void async_init(socket_init_callback callback) {
m_connection.get_handler()->on_tcp_init();
// TODO: make configuration option for NO_DELAY
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
// TODO: should this use post()?
callback(boost::system::error_code());
}
bool shutdown() {
boost::system::error_code ignored_ec;
m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both,ignored_ec);
if (ignored_ec) {
return false;
} else {
@@ -120,9 +120,9 @@ private:
boost::asio::io_service& m_io_service;
};
} // namespace socket
} // namespace websocketpp
} // namespace websocketpp_02
#ifdef _MSC_VER
# pragma warning(pop)

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,38 +22,38 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_SOCKET_BASE_HPP
#define WEBSOCKETPP_SOCKET_BASE_HPP
/*
websocketpp::socket API
websocketpp_02::socket API
endpoint policy that provides:
nested connection policy called `connection` that provides:
- constructor that takes a reference to the endpoint_policy
- async_init
- async_read_some
- async_write_some
- get_raw_socket
*/
#include <boost/system/error_code.hpp>
#include <boost/function.hpp>
namespace websocketpp {
namespace websocketpp_02 {
namespace socket {
typedef boost::function<void(const boost::system::error_code&)> socket_init_callback;
} // namespace socket
} // namespace websocketpp
} // namespace websocketpp_02

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#error Use auto TLS only
@@ -39,7 +39,7 @@
#include <iostream>
namespace websocketpp {
namespace websocketpp_02 {
namespace socket {
template <typename endpoint_type>
@@ -48,7 +48,7 @@ public:
typedef tls<endpoint_type> type;
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> tls_socket;
typedef boost::shared_ptr<tls_socket> tls_socket_ptr;
// should be private friended
boost::asio::io_service& get_io_service() {
return m_io_service;
@@ -65,19 +65,19 @@ public:
return boost::asio::ssl::stream_base::client;
}
}
bool is_secure() {
return true;
}
class handler_interface {
public:
virtual ~handler_interface() {}
virtual void on_tcp_init() {};
virtual boost::asio::ssl::context& on_tls_init() = 0;
};
// Connection specific details
template <typename connection_type>
class connection {
@@ -86,11 +86,11 @@ public:
tls_socket::lowest_layer_type& get_raw_socket() {
return m_socket_ptr->lowest_layer();
}
tls_socket& get_socket() {
return *m_socket_ptr;
}
bool is_secure() {
return true;
}
@@ -98,26 +98,26 @@ public:
connection(tls<endpoint_type>& e)
: m_endpoint(e)
, m_connection(static_cast< connection_type& >(*this)) {}
void init()
{
boost::asio::ssl::context& ssl_context (
m_connection.get_handler()->get_ssl_context ());
m_socket_ptr = tls_socket_ptr (new tls_socket (
m_endpoint.get_io_service(), ssl_context));
}
void async_init(boost::function<void(const boost::system::error_code&)> callback)
{
m_connection.get_handler()->on_tcp_init();
// wait for TLS handshake
// TODO: configurable value
m_connection.register_timeout(5000,
fail::status::TIMEOUT_TLS,
"Timeout on TLS handshake");
m_socket_ptr->async_handshake(
m_endpoint.get_handshake_type(),
boost::bind(
@@ -128,17 +128,17 @@ public:
)
);
}
void handle_init(socket_init_callback callback,const boost::system::error_code& error) {
m_connection.cancel_timeout();
callback(error);
}
// note, this function for some reason shouldn't/doesn't need to be
// note, this function for some reason shouldn't/doesn't need to be
// called for plain HTTP connections. not sure why.
bool shutdown() {
boost::system::error_code ignored_ec;
m_socket_ptr->async_shutdown( // Don't block on connection shutdown DJS
boost::bind(
&tls<endpoint_type>::handle_shutdown,
@@ -146,7 +146,7 @@ public:
boost::asio::placeholders::error
)
);
if (ignored_ec) {
return false;
} else {
@@ -165,8 +165,8 @@ private:
boost::asio::io_service& m_io_service;
tls_socket::handshake_type m_handshake_type;
};
} // namespace socket
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKETPP_SOCKET_TLS_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include "uri.hpp"
@@ -32,7 +32,7 @@
#include <boost/regex.hpp>
using websocketpp::uri;
using websocketpp_02::uri;
uri::uri(const std::string& uri) {
// temporary testing non-regex implimentation.
@@ -45,10 +45,10 @@ uri::uri(const std::string& uri) {
READ_PORT = 5,
READ_RESOURCE = 6,
};
state the_state = BEGIN;
std::string temp;
for (std::string::const_iterator it = uri.begin(); it != uri.end(); it++) {
switch (the_state) {
case BEGIN:
@@ -56,9 +56,9 @@ uri::uri(const std::string& uri) {
if (temp.size() < 6) {
temp.append(1,*it);
} else {
throw websocketpp::uri_exception("Scheme is too long");
throw websocketpp_02::uri_exception("Scheme is too long");
}
if (temp == "ws://") {
m_secure = false;
the_state = HOST_BEGIN;
@@ -85,11 +85,11 @@ uri::uri(const std::string& uri) {
the_state = BEGIN_PORT;
break;
}
if (m_host.size() > 45) {
throw websocketpp::uri_exception("IPv6 literal is too long");
throw websocketpp_02::uri_exception("IPv6 literal is too long");
}
if (*it == '.' ||
*it == ':' ||
(*it >= '0' && *it <= '9') ||
@@ -106,15 +106,15 @@ uri::uri(const std::string& uri) {
the_state = BEGIN_PORT;
break;
}
if (*it == '/') {
it--;
the_state = BEGIN_PORT;
break;
}
// TODO: max url length?
// TODO: check valid characters?
if (1) {
m_host.append(1,*it);
@@ -128,7 +128,7 @@ uri::uri(const std::string& uri) {
*it--;
the_state = READ_RESOURCE;
} else {
throw websocketpp::uri_exception("Error parsing WebSocket URI");
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
}
break;
case READ_PORT:
@@ -136,30 +136,30 @@ uri::uri(const std::string& uri) {
if (temp.size() < 5) {
temp.append(1,*it);
} else {
throw websocketpp::uri_exception("Port is too long");
throw websocketpp_02::uri_exception("Port is too long");
}
} else if (*it == '/') {
m_port = get_port_from_string(temp);
temp.clear();
*it--;
the_state = READ_RESOURCE;
} else {
throw websocketpp::uri_exception("Error parsing WebSocket URI");
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
}
break;
case READ_RESOURCE:
// max length check?
if (*it == '#') {
throw websocketpp::uri_exception("WebSocket URIs cannot have fragments");
throw websocketpp_02::uri_exception("WebSocket URIs cannot have fragments");
} else {
m_resource.append(1,*it);
}
break;
}
}
switch (the_state) {
case READ_PORT:
m_port = get_port_from_string(temp);
@@ -167,65 +167,65 @@ uri::uri(const std::string& uri) {
default:
break;
}
if (m_resource == "") {
m_resource = "/";
}*/
boost::cmatch matches;
const boost::regex expression("(ws|wss)://([^/:\\[]+|\\[[0-9a-fA-F:.]+\\])(:\\d{1,5})?(/[^#]*)?");
// TODO: should this split resource into path/query?
if (boost::regex_match(uri.c_str(), matches, expression)) {
m_secure = (matches[1] == "wss");
m_host = matches[2];
// strip brackets from IPv6 literal URIs
if (m_host[0] == '[') {
m_host = m_host.substr(1,m_host.size()-2);
}
std::string port(matches[3]);
if (port != "") {
// strip off the :
// this could probably be done with a better regex.
port = port.substr(1);
}
m_port = get_port_from_string(port);
m_resource = matches[4];
if (m_resource == "") {
m_resource = "/";
}
return;
}
throw websocketpp::uri_exception("Error parsing WebSocket URI");
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
}
uri::uri(bool secure, const std::string& host, uint16_t port, const std::string& resource)
uri::uri(bool secure, const std::string& host, uint16_t port, const std::string& resource)
: m_secure(secure),
m_host(host),
m_host(host),
m_port(port),
m_resource(resource == "" ? "/" : resource) {}
uri::uri(bool secure, const std::string& host, const std::string& resource)
uri::uri(bool secure, const std::string& host, const std::string& resource)
: m_secure(secure),
m_host(host),
m_host(host),
m_port(m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT),
m_resource(resource == "" ? "/" : resource) {}
uri::uri(bool secure,
const std::string& host,
const std::string& port,
const std::string& resource)
uri::uri(bool secure,
const std::string& host,
const std::string& port,
const std::string& resource)
: m_secure(secure),
m_host(host),
m_port(get_port_from_string(port)),
@@ -233,24 +233,24 @@ uri::uri(bool secure,
/* Slightly cleaner C++11 delegated constructor method
uri::uri(bool secure,
const std::string& host,
uint16_t port,
const std::string& resource)
uri::uri(bool secure,
const std::string& host,
uint16_t port,
const std::string& resource)
: m_secure(secure),
m_host(host),
m_host(host),
m_port(port),
m_resource(resource == "" ? "/" : resource)
{
if (m_port > 65535) {
throw websocketpp::uri_exception("Port must be less than 65535");
throw websocketpp_02::uri_exception("Port must be less than 65535");
}
}
uri::uri(bool secure,
const std::string& host,
const std::string& port,
const std::string& resource)
uri::uri(bool secure,
const std::string& host,
const std::string& port,
const std::string& resource)
: uri(secure, host, get_port_from_string(port), resource) {}
*/
@@ -271,7 +271,7 @@ std::string uri::get_host_port() const {
p << m_host << ":" << m_port;
return p.str();
}
}
uint16_t uri::get_port() const {
@@ -290,13 +290,13 @@ std::string uri::get_resource() const {
std::string uri::str() const {
std::stringstream s;
s << "ws" << (m_secure ? "s" : "") << "://" << m_host;
if (m_port != (m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT)) {
s << ":" << m_port;
}
s << m_resource;
return s.str();
}
@@ -305,16 +305,16 @@ uint16_t uri::get_port_from_string(const std::string& port) const {
if (port == "") {
return (m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT);
}
unsigned int t_port = atoi(port.c_str());
if (t_port > 65535) {
throw websocketpp::uri_exception("Port must be less than 65535");
throw websocketpp_02::uri_exception("Port must be less than 65535");
}
if (t_port == 0) {
throw websocketpp::uri_exception("Error parsing port string: "+port);
throw websocketpp_02::uri_exception("Error parsing port string: "+port);
}
return static_cast<uint16_t>(t_port);
}

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_URI_HPP
@@ -32,12 +32,12 @@
#include <exception>
namespace websocketpp {
namespace websocketpp_02 {
// WebSocket URI only (not http/etc)
// WebSocket URI only (not http/etc)
class uri_exception : public std::exception {
public:
public:
uri_exception(const std::string& msg) : m_msg(msg) {}
~uri_exception() throw() {}
@@ -58,7 +58,7 @@ public:
uri(bool secure, const std::string& host, uint16_t port, const std::string& resource);
uri(bool secure, const std::string& host, const std::string& resource);
uri(bool secure, const std::string& host, const std::string& port, const std::string& resource);
bool get_secure() const;
std::string get_host() const;
std::string get_host_port() const;
@@ -66,20 +66,20 @@ public:
std::string get_port_str() const;
std::string get_resource() const;
std::string str() const;
// get query?
// get fragment
// hi <3
// get the string representation of this URI
//std::string base() const; // is this still needed?
// setter methods set some or all (in the case of parse) based on the input.
// These functions throw a uri_exception on failure.
/*void set_uri(const std::string& uri);
void set_secure(bool secure);
void set_host(const std::string& host);
void set_port(uint16_t port);
@@ -87,7 +87,7 @@ public:
void set_resource(const std::string& resource);*/
private:
uint16_t get_port_from_string(const std::string& port) const;
bool m_secure;
std::string m_host;
uint16_t m_port;
@@ -96,6 +96,6 @@ private:
typedef boost::shared_ptr<uri> uri_ptr;
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKETPP_URI_HPP

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKET_FRAME_HPP
@@ -49,18 +49,18 @@
#include <iostream>
#include <algorithm>
namespace websocketpp {
namespace websocketpp_02 {
namespace frame {
/* policies to abstract out
- random number generation
- utf8 validation
rng
int32_t gen()
class boost_random {
public:
boost_random()
@@ -69,9 +69,9 @@ private:
boost::random::random_device m_rng;
boost::random::variate_generator<boost::random::random_device&,boost::random::uniform_int_distribution<> > m_gen;
}
*/
template <class rng_policy>
class parser : boost::noncopyable {
public:
@@ -83,20 +83,20 @@ public:
static const uint8_t BPB0_FIN = 0x80;
static const uint8_t BPB1_PAYLOAD = 0x7F;
static const uint8_t BPB1_MASK = 0x80;
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
static const unsigned int BASIC_HEADER_LENGTH = 2;
static const unsigned int BASIC_HEADER_LENGTH = 2;
static const unsigned int MAX_HEADER_LENGTH = 14;
static const uint8_t extended_header_length = 12;
static const uint64_t max_payload_size = 100000000; // 100MB
// create an empty frame for writing into
parser(rng_policy& rng) : m_rng(rng) {
reset();
}
bool ready() const {
return (m_state == STATE_READY);
}
@@ -110,8 +110,8 @@ public:
m_payload.clear();
std::fill(m_header,m_header+MAX_HEADER_LENGTH,0);
}
// Method invariant: One of the following must always be true even in the case
// Method invariant: One of the following must always be true even in the case
// of exceptions.
// - m_bytes_needed > 0
// - m-state = STATE_READY
@@ -120,23 +120,23 @@ public:
switch (m_state) {
case STATE_BASIC_HEADER:
s.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
process_basic_header();
validate_basic_header();
if (m_bytes_needed > 0) {
m_state = STATE_EXTENDED_HEADER;
} else {
process_extended_header();
if (m_bytes_needed == 0) {
m_state = STATE_READY;
process_payload();
} else {
m_state = STATE_PAYLOAD;
}
@@ -145,9 +145,9 @@ public:
break;
case STATE_EXTENDED_HEADER:
s.read(&m_header[get_header_len()-m_bytes_needed],m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
process_extended_header();
if (m_bytes_needed == 0) {
@@ -161,9 +161,9 @@ public:
case STATE_PAYLOAD:
s.read(reinterpret_cast<char *>(&m_payload[m_payload.size()-m_bytes_needed]),
m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
m_state = STATE_READY;
process_payload();
@@ -174,9 +174,9 @@ public:
// of a close frame.
do {
s.read(reinterpret_cast<char *>(&m_header[0]),1);
//std::cout << std::hex << int(static_cast<unsigned char>(m_header[0])) << " ";
if (int(static_cast<unsigned char>(m_header[0])) == 0x88) {
//(BPB0_FIN && CONNECTION_CLOSE)
m_bytes_needed--;
@@ -184,19 +184,19 @@ public:
break;
}
} while (s.gcount() > 0);
//std::cout << std::endl;
break;
default:
break;
}
/*if (s.gcount() == 0) {
throw frame_error("consume read zero bytes",FERR_FATAL_SESSION_ERROR);
}*/
} catch (const processor::exception& e) {
// After this point all non-close frames must be considered garbage,
// After this point all non-close frames must be considered garbage,
// including the current one. Reset it and put the reading frame into
// a recovery state.
if (m_degraded == true) {
@@ -205,12 +205,12 @@ public:
reset();
m_state = STATE_RECOVERY;
m_degraded = true;
throw e;
}
}
}
// get pointers to underlying buffers
char* get_header() {
return m_header;
@@ -220,20 +220,20 @@ public:
}
unsigned int get_header_len() const {
unsigned int temp = 2;
if (get_masked()) {
temp += 4;
}
if (get_basic_size() == 126) {
temp += 2;
} else if (get_basic_size() == 127) {
temp += 8;
}
return temp;
}
char* get_masking_key() {
/*if (m_state != STATE_READY) {
std::cout << "throw" << std::endl;
@@ -241,7 +241,7 @@ public:
}*/
return &m_header[get_header_len()-4];
}
// get and set header bits
bool get_fin() const {
return ((m_header[0] & BPB0_FIN) == BPB0_FIN);
@@ -253,7 +253,7 @@ public:
m_header[0] &= (0xFF ^ BPB0_FIN);
}
}
bool get_rsv1() const {
return ((m_header[0] & BPB0_RSV1) == BPB0_RSV1);
}
@@ -264,7 +264,7 @@ public:
m_header[0] &= (0xFF ^ BPB0_RSV1);
}
}
bool get_rsv2() const {
return ((m_header[0] & BPB0_RSV2) == BPB0_RSV2);
}
@@ -275,7 +275,7 @@ public:
m_header[0] &= (0xFF ^ BPB0_RSV2);
}
}
bool get_rsv3() const {
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
}
@@ -286,7 +286,7 @@ public:
m_header[0] &= (0xFF ^ BPB0_RSV3);
}
}
opcode::value get_opcode() const {
return frame::opcode::value(m_header[0] & BPB0_OPCODE);
}
@@ -294,19 +294,19 @@ public:
if (opcode::reserved(op)) {
throw processor::exception("reserved opcode",processor::error::PROTOCOL_VIOLATION);
}
if (opcode::invalid(op)) {
throw processor::exception("invalid opcode",processor::error::PROTOCOL_VIOLATION);
}
if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) {
throw processor::exception("control frames can't have large payloads",processor::error::PROTOCOL_VIOLATION);
}
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
m_header[0] |= op; // set op bits
}
bool get_masked() const {
return ((m_header[1] & BPB1_MASK) == BPB1_MASK);
}
@@ -319,7 +319,7 @@ public:
clear_masking_key();
}
}
uint8_t get_basic_size() const {
return m_header[1] & BPB1_PAYLOAD;
}
@@ -328,10 +328,10 @@ public:
// TODO: how to handle errors like this?
throw "attempted to get payload size before reading full header";
}
return m_payload.size();
}
close::status::value get_close_status() const {
if (get_payload_size() == 0) {
return close::status::NO_STATUS;
@@ -339,9 +339,9 @@ public:
char val[2] = { m_payload[0], m_payload[1] };
uint16_t code;
std::copy(val,val+sizeof(code),&code);
std::copy(val,val+sizeof(code),&code);
code = ntohs(code);
return close::status::value(code);
} else {
return close::status::PROTOCOL_ERROR;
@@ -360,38 +360,38 @@ public:
return std::string();
}
}
std::vector<unsigned char> &get_payload() {
return m_payload;
}
void set_payload(const std::vector<unsigned char>& source) {
set_payload_helper(source.size());
std::copy(source.begin(),source.end(),m_payload.begin());
}
void set_payload(const std::string& source) {
set_payload_helper(source.size());
std::copy(source.begin(),source.end(),m_payload.begin());
}
void set_payload_helper(size_t s) {
if (s > max_payload_size) {
throw processor::exception("requested payload is over implementation defined limit",processor::error::MESSAGE_TOO_BIG);
}
// limits imposed by the websocket spec
if (is_control() && s > limits::PAYLOAD_SIZE_BASIC) {
throw processor::exception("control frames can't have large payloads",processor::error::PROTOCOL_VIOLATION);
}
bool masked = get_masked();
if (s <= limits::PAYLOAD_SIZE_BASIC) {
m_header[1] = s;
} else if (s <= limits::PAYLOAD_SIZE_EXTENDED) {
m_header[1] = BASIC_PAYLOAD_16BIT_CODE;
// this reinterprets the second pair of bytes in m_header as a
// 16 bit int and writes the payload size there as an integer
// in network byte order
@@ -402,14 +402,14 @@ public:
} else {
throw processor::exception("payload size limit is 63 bits",processor::error::PROTOCOL_VIOLATION);
}
if (masked) {
m_header[1] |= BPB1_MASK;
}
m_payload.resize(s);
}
void set_status(close::status::value status,const std::string message = "") {
// check for valid statuses
if (close::status::invalid(status)) {
@@ -417,42 +417,42 @@ public:
err << "Status code " << status << " is invalid";
throw processor::exception(err.str());
}
if (close::status::reserved(status)) {
std::stringstream err;
err << "Status code " << status << " is reserved";
throw processor::exception(err.str());
}
m_payload.resize(2+message.size());
char val[2];
*reinterpret_cast<uint16_t*>(&val[0]) = htons(status);
bool masked = get_masked();
m_header[1] = message.size()+2;
if (masked) {
m_header[1] |= BPB1_MASK;
}
m_payload[0] = val[0];
m_payload[1] = val[1];
std::copy(message.begin(),message.end(),m_payload.begin()+2);
}
bool is_control() const {
return (opcode::is_control(get_opcode()));
}
std::string print_frame() const {
std::stringstream f;
unsigned int len = get_header_len();
f << "frame: ";
// print header
for (unsigned int i = 0; i < len; i++) {
@@ -469,7 +469,7 @@ public:
}
return f.str();
}
// reads basic header, sets and returns m_header_bits_needed
void process_basic_header() {
m_bytes_needed = get_header_len() - BASIC_HEADER_LENGTH;
@@ -478,43 +478,43 @@ public:
uint8_t s = get_basic_size();
uint64_t payload_size;
int mask_index = BASIC_HEADER_LENGTH;
if (s <= limits::PAYLOAD_SIZE_BASIC) {
payload_size = s;
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
// reinterpret the second two bytes as a 16 bit integer in network
// byte order. Convert to host byte order and store locally.
payload_size = ntohs(*(
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (payload_size < s) {
std::stringstream err;
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << payload_size;
m_bytes_needed = payload_size;
throw processor::exception(err.str(),processor::error::PROTOCOL_VIOLATION);
}
mask_index += 2;
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
// reinterpret the second eight bytes as a 64 bit integer in
// reinterpret the second eight bytes as a 64 bit integer in
// network byte order. Convert to host byte order and store.
payload_size = zsutil::ntohll(*(
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (payload_size <= limits::PAYLOAD_SIZE_EXTENDED) {
m_bytes_needed = payload_size;
throw processor::exception("payload length not minimally encoded",
processor::error::PROTOCOL_VIOLATION);
}
mask_index += 8;
} else {
// TODO: shouldn't be here how to handle?
throw processor::exception("invalid get_basic_size in process_extended_header");
}
if (get_masked() == 0) {
clear_masking_key();
} else {
@@ -526,60 +526,60 @@ public:
m_masking_key[2] = m_header[mask_index+2];
m_masking_key[3] = m_header[mask_index+3];*/
}
if (payload_size > max_payload_size) {
// TODO: frame/message size limits
// TODO: find a way to throw a server error without coupling frame
// with server
// throw websocketpp::server_error("got frame with payload greater than maximum frame buffer size.");
// throw websocketpp_02::server_error("got frame with payload greater than maximum frame buffer size.");
throw "Got frame with payload greater than maximum frame buffer size.";
}
m_payload.resize(payload_size);
m_bytes_needed = payload_size;
}
void process_payload() {
if (get_masked()) {
char *masking_key = get_masking_key();
for (uint64_t i = 0; i < m_payload.size(); i++) {
m_payload[i] = (m_payload[i] ^ masking_key[i%4]);
}
}
}
// experiment with more efficient masking code.
void process_payload2() {
// unmask payload one byte at a time
//uint64_t key = (*((uint32_t*)m_masking_key;)) << 32;
//key += *((uint32_t*)m_masking_key);
// might need to switch byte order
/*uint32_t key = *((uint32_t*)m_masking_key);
// 4
uint64_t i = 0;
uint64_t s = (m_payload.size() / 4);
std::cout << "s: " << s << std::endl;
// chunks of 4
for (i = 0; i < s; i+=4) {
((uint32_t*)(&m_payload[0]))[i] = (((uint32_t*)(&m_payload[0]))[i] ^ key);
}
// finish the last few
for (i = s; i < m_payload.size(); i++) {
m_payload[i] = (m_payload[i] ^ m_masking_key[i%4]);
}*/
}
void validate_utf8(uint32_t* state,uint32_t* codep,size_t offset = 0) const {
for (size_t i = offset; i < m_payload.size(); i++) {
using utf8_validator::decode;
if (decode(state,codep,m_payload[i]) == utf8_validator::UTF8_REJECT) {
throw processor::exception("Invalid UTF-8 Data",processor::error::PAYLOAD_VIOLATION);
}
@@ -590,23 +590,23 @@ public:
if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) {
throw processor::exception("Control Frame is too large",processor::error::PROTOCOL_VIOLATION);
}
// check for reserved bits
if (get_rsv1() || get_rsv2() || get_rsv3()) {
throw processor::exception("Reserved bit used",processor::error::PROTOCOL_VIOLATION);
}
// check for reserved opcodes
if (opcode::reserved(get_opcode())) {
throw processor::exception("Reserved opcode used",processor::error::PROTOCOL_VIOLATION);
}
// check for fragmented control message
if (is_control() && !get_fin()) {
throw processor::exception("Fragmented control message",processor::error::PROTOCOL_VIOLATION);
}
}
void generate_masking_key() {
*(reinterpret_cast<int32_t *>(&m_header[get_header_len()-4])) = m_rng.rand();
}
@@ -615,21 +615,21 @@ public:
// method to not include these byte ranges. Whenever the masking bit is re-
// set a new key is generated anyways.
}
private:
static const uint8_t STATE_BASIC_HEADER = 1;
static const uint8_t STATE_EXTENDED_HEADER = 2;
static const uint8_t STATE_PAYLOAD = 3;
static const uint8_t STATE_READY = 4;
static const uint8_t STATE_RECOVERY = 5;
uint8_t m_state;
uint64_t m_bytes_needed;
bool m_degraded;
char m_header[MAX_HEADER_LENGTH];
std::vector<unsigned char> m_payload;
rng_policy& m_rng;
};

View File

@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,7 +22,7 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_HPP
@@ -31,33 +31,33 @@
#include "common.hpp"
#include "endpoint.hpp"
namespace websocketpp {
namespace websocketpp_02 {
#ifdef WEBSOCKETPP_ROLE_SERVER_HPP
#ifdef WEBSOCKETPP_SOCKET_PLAIN_HPP
typedef websocketpp::endpoint<websocketpp::role::server,
websocketpp::socket::plain> server;
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
websocketpp_02::socket::plain> server;
#endif
#ifdef WEBSOCKETPP_SOCKET_TLS_HPP
typedef websocketpp::endpoint<websocketpp::role::server,
websocketpp::socket::tls> server_tls;
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
websocketpp_02::socket::tls> server_tls;
#endif
#ifdef WEBSOCKETPP_SOCKET_AUTOTLS_HPP
typedef websocketpp::endpoint<websocketpp::role::server,
websocketpp::socket::autotls> server_autotls;
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
websocketpp_02::socket::autotls> server_autotls;
#endif
#endif
#ifdef WEBSOCKETPP_ROLE_CLIENT_HPP
#ifdef WEBSOCKETPP_SOCKET_PLAIN_HPP
typedef websocketpp::endpoint<websocketpp::role::client,
websocketpp::socket::plain> client;
typedef websocketpp_02::endpoint<websocketpp_02::role::client,
websocketpp_02::socket::plain> client;
#endif
#ifdef WEBSOCKETPP_SOCKET_TLS_HPP
typedef websocketpp::endpoint<websocketpp::role::client,
websocketpp::socket::tls> client_tls;
typedef websocketpp_02::endpoint<websocketpp_02::role::client,
websocketpp_02::socket::tls> client_tls;
#endif
#endif
} // namespace websocketpp
} // namespace websocketpp_02
#endif // WEBSOCKETPP_HPP