Updating websocket++ to latest github release (0.3 alpha4).

This commit is contained in:
lotodore
2013-10-11 23:54:30 +02:00
parent 2d6db51465
commit 0368b57432
23 changed files with 732 additions and 627 deletions
+122
View File
@@ -1,3 +1,5 @@
Main Library:
Copyright (c) 2013, Peter Thorson. All rights reserved. Copyright (c) 2013, Peter Thorson. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -21,3 +23,123 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Bundled Libraries:
****** Base 64 Library (base64/base64.hpp) ******
base64.hpp is a repackaging of the base64.cpp and base64.h files into a
single header suitable for use as a header only library. This conversion was
done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
the code are redistributed under the same license as the original, which is
listed below.
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
****** SHA1 Library (sha1/sha1.hpp) ******
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
library (http://code.google.com/p/smallsha1/) into a single header suitable for
use as a header only library. This conversion was done by Peter Thorson
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
under the same license as the original, which is listed below.
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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.
****** MD5 Library (common/md5.hpp) ******
md5.hpp is a reformulation of the md5.h and md5.c code from
http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
function as a component of a header only library. This conversion was done by
Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
changes are released under the same license as the original (listed below)
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
****** UTF8 Validation logic (utf8_validation.hpp) ******
utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann
<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for
details.
The original license:
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
****** ******
base64.hpp is a repackaging of the base64.cpp and base64.h files into a base64.hpp is a repackaging of the base64.cpp and base64.h files into a
single headersuitable for use as a header only library. This conversion was single header suitable for use as a header only library. This conversion was
done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
the code are redistributed under the same license as the original, which is the code are redistributed under the same license as the original, which is
listed below. listed below.
+4 -3
View File
@@ -1,7 +1,8 @@
/* /*
md5.hpp is a reformulation of the md5.h and md5.c code to allow it to function md5.hpp is a reformulation of the md5.h and md5.c code from
as a component of a header only library. This conversion was done by Peter http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The function as a component of a header only library. This conversion was done by
Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
changes are released under the same license as the original (listed below) changes are released under the same license as the original (listed below)
*/ */
/* /*
+7 -4
View File
@@ -229,30 +229,37 @@ public:
m_close_handler = h; m_close_handler = h;
} }
void set_fail_handler(fail_handler h) { void set_fail_handler(fail_handler h) {
m_alog.write(log::alevel::devel,"set_fail_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_fail_handler = h; m_fail_handler = h;
} }
void set_ping_handler(ping_handler h) { void set_ping_handler(ping_handler h) {
m_alog.write(log::alevel::devel,"set_ping_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_ping_handler = h; m_ping_handler = h;
} }
void set_pong_handler(pong_handler h) { void set_pong_handler(pong_handler h) {
m_alog.write(log::alevel::devel,"set_pong_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_pong_handler = h; m_pong_handler = h;
} }
void set_pong_timeout_handler(pong_timeout_handler h) { void set_pong_timeout_handler(pong_timeout_handler h) {
m_alog.write(log::alevel::devel,"set_pong_timeout_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_pong_timeout_handler = h; m_pong_timeout_handler = h;
} }
void set_interrupt_handler(interrupt_handler h) { void set_interrupt_handler(interrupt_handler h) {
m_alog.write(log::alevel::devel,"set_interrupt_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_interrupt_handler = h; m_interrupt_handler = h;
} }
void set_http_handler(http_handler h) { void set_http_handler(http_handler h) {
m_alog.write(log::alevel::devel,"set_http_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_http_handler = h; m_http_handler = h;
} }
void set_validate_handler(validate_handler h) { void set_validate_handler(validate_handler h) {
m_alog.write(log::alevel::devel,"set_validate_handler");
scoped_lock_type guard(m_mutex); scoped_lock_type guard(m_mutex);
m_validate_handler = h; m_validate_handler = h;
} }
@@ -390,7 +397,6 @@ public:
} }
protected: protected:
connection_ptr create_connection(); connection_ptr create_connection();
void remove_connection(connection_ptr con);
alog_type m_alog; alog_type m_alog;
elog_type m_elog; elog_type m_elog;
@@ -411,9 +417,6 @@ private:
rng_type m_rng; rng_type m_rng;
// endpoint resources
std::set<connection_ptr> m_connections;
// static settings // static settings
bool const m_is_server; bool const m_is_server;
@@ -1177,27 +1177,27 @@ void connection<config>::handle_send_http_response(
this->log_open_result(); this->log_open_result();
if (m_handshake_timer) {
m_handshake_timer->cancel();
m_handshake_timer.reset();
}
if (m_response.get_status_code() != http::status_code::switching_protocols) if (m_response.get_status_code() != http::status_code::switching_protocols)
{ {
if (m_processor) { if (m_processor) {
// 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 // this was a websocket connection that ended in an error
std::stringstream s; std::stringstream s;
s << "Handshake ended with HTTP error: " s << "Handshake ended with HTTP error: "
<< m_response.get_status_code(); << m_response.get_status_code();
m_elog.write(log::elevel::rerror,s.str()); m_elog.write(log::elevel::rerror,s.str());
} else {
// if this was not a websocket connection, we have written
// the expected response and the connection can be closed.
} }
this->terminate(make_error_code(error::http_connection_ended)); this->terminate(make_error_code(error::http_connection_ended));
return; return;
} }
if (m_handshake_timer) {
m_handshake_timer->cancel();
m_handshake_timer.reset();
}
this->atomic_state_change( this->atomic_state_change(
istate::PROCESS_HTTP_REQUEST, istate::PROCESS_HTTP_REQUEST,
istate::PROCESS_CONNECTION, istate::PROCESS_CONNECTION,
@@ -1339,6 +1339,11 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
m_alog.write(log::alevel::devel,std::string("Raw response: ")+m_response.raw()); m_alog.write(log::alevel::devel,std::string("Raw response: ")+m_response.raw());
if (m_response.headers_ready()) { if (m_response.headers_ready()) {
if (m_handshake_timer) {
m_handshake_timer->cancel();
m_handshake_timer.reset();
}
lib::error_code ec = m_processor->validate_server_handshake_response( lib::error_code ec = m_processor->validate_server_handshake_response(
m_request, m_request,
m_response m_response
@@ -1361,11 +1366,6 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
"handle_read_http_response must be called from READ_HTTP_RESPONSE state" "handle_read_http_response must be called from READ_HTTP_RESPONSE state"
); );
if (m_handshake_timer) {
m_handshake_timer->cancel();
m_handshake_timer.reset();
}
this->log_open_result(); this->log_open_result();
if (m_open_handler) { if (m_open_handler) {
@@ -50,9 +50,6 @@ endpoint<connection,config>::create_connection() {
// Cast that weak pointer to void* and manage it using another shared_ptr // Cast that weak pointer to void* and manage it using another shared_ptr
// connection_hdl hdl(reinterpret_cast<void*>(new connection_weak_ptr(con))); // connection_hdl hdl(reinterpret_cast<void*>(new connection_weak_ptr(con)));
// con->set_handle(hdl);
//
con->set_handle(w); con->set_handle(w);
// Copy default handlers from the endpoint // Copy default handlers from the endpoint
@@ -67,14 +64,6 @@ endpoint<connection,config>::create_connection() {
con->set_validate_handler(m_validate_handler); con->set_validate_handler(m_validate_handler);
con->set_message_handler(m_message_handler); con->set_message_handler(m_message_handler);
con->set_termination_handler(
lib::bind(
&type::remove_connection,
this,
lib::placeholders::_1
)
);
lib::error_code ec; lib::error_code ec;
ec = transport_type::init(con); ec = transport_type::init(con);
@@ -83,9 +72,6 @@ endpoint<connection,config>::create_connection() {
return connection_ptr(); return connection_ptr();
} }
scoped_lock_type lock(m_mutex);
m_connections.insert(con);
return con; return con;
} }
@@ -216,20 +202,6 @@ void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
if (ec) { throw ec; } if (ec) { throw ec; }
} }
template <typename connection, typename config>
void endpoint<connection,config>::remove_connection(connection_ptr con) {
std::stringstream s;
s << "remove_connection. New count: " << m_connections.size()-1;
m_alog.write(log::alevel::devel,s.str());
scoped_lock_type lock(m_mutex);
// unregister the termination handler
con->set_termination_handler(termination_handler());
m_connections.erase(con);
}
} // namespace websocketpp } // namespace websocketpp
#endif // WEBSOCKETPP_ENDPOINT_IMPL_HPP #endif // WEBSOCKETPP_ENDPOINT_IMPL_HPP
@@ -614,27 +614,11 @@ protected:
lib::error_code process_handshake_key(std::string & key) const { lib::error_code process_handshake_key(std::string & key) const {
key.append(constants::handshake_guid); key.append(constants::handshake_guid);
sha1 sha; unsigned char message_digest[20];
uint32_t message_digest[5]; sha1::calc(key.c_str(),key.length(),message_digest);
key = base64_encode(message_digest,20);
sha << key.c_str();
if (sha.get_raw_digest(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]);
}
key = base64_encode(
reinterpret_cast<unsigned char const *>(message_digest),
20
);
return lib::error_code(); return lib::error_code();
} else {
return error::make_error_code(error::sha1_library);
}
} }
/// Reads bytes from buf into m_basic_header /// Reads bytes from buf into m_basic_header
@@ -66,8 +66,7 @@ public:
explicit client() : endpoint_type(false) explicit client() : endpoint_type(false)
{ {
endpoint_type::m_alog.write(log::alevel::devel, endpoint_type::m_alog.write(log::alevel::devel, "client constructor");
"client constructor");
} }
/// Get a new connection /// Get a new connection
@@ -77,15 +76,17 @@ public:
* applying connection specific settings before performing the opening * applying connection specific settings before performing the opening
* handshake. * handshake.
* *
* @param [in] location URI to open the connection to as a uri_ptr
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection * @return A connection_ptr to the new connection
*/ */
connection_ptr get_connection(uri_ptr location, lib::error_code &ec) { connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {
if (location->get_secure() && !transport_type::is_secure()) { if (location->get_secure() && !transport_type::is_secure()) {
ec = error::make_error_code(error::endpoint_not_secure); ec = error::make_error_code(error::endpoint_not_secure);
return connection_ptr(); return connection_ptr();
} }
// create connection
connection_ptr con = endpoint_type::create_connection(); connection_ptr con = endpoint_type::create_connection();
if (!con) { if (!con) {
@@ -95,7 +96,6 @@ public:
con->set_uri(location); con->set_uri(location);
// Success
ec = lib::error_code(); ec = lib::error_code();
return con; return con;
} }
@@ -106,10 +106,12 @@ public:
* suitable for passing to connect(connection_ptr). This overload allows * suitable for passing to connect(connection_ptr). This overload allows
* default construction of the uri_ptr from a standard string. * default construction of the uri_ptr from a standard string.
* *
* @param [in] u URI to open the connection to as a string
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection * @return A connection_ptr to the new connection
*/ */
connection_ptr get_connection(const std::string& u, lib::error_code &ec) { connection_ptr get_connection(std::string const & u, lib::error_code & ec) {
// parse uri
uri_ptr location(new uri(u)); uri_ptr location(new uri(u));
if (!location->get_valid()) { if (!location->get_valid()) {
@@ -137,35 +139,17 @@ public:
lib::bind( lib::bind(
&type::handle_connect, &type::handle_connect,
this, this,
lib::placeholders::_1, con,
lib::placeholders::_2 lib::placeholders::_1
) )
); );
return con; return con;
} }
// connect(...)
private: private:
// handle_connect // handle_connect
void handle_connect(connection_hdl hdl, const lib::error_code & ec) { void handle_connect(connection_ptr con, lib::error_code const & ec) {
lib::error_code hdl_ec; if (ec) {
connection_ptr con = endpoint_type::get_con_from_hdl(hdl,hdl_ec);
if (hdl_ec == error::bad_connection) {
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_connect got an invalid handle back");
} else if (hdl_ec) {
// There was some other unknown error attempting to convert the hdl
// to a connection.
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_connect error in get_con_from_hdl: "+hdl_ec.message());
//con->terminate();
} else if (ec) {
// TODO
// Set connection's failure reasons
con->terminate(ec); con->terminate(ec);
endpoint_type::m_elog.write(log::elevel::rerror, endpoint_type::m_elog.write(log::elevel::rerror,
@@ -90,29 +90,13 @@ public:
lib::bind( lib::bind(
&type::handle_accept, &type::handle_accept,
this, this,
lib::placeholders::_1, con,
lib::placeholders::_2 lib::placeholders::_1
) )
); );
} }
void handle_accept(connection_hdl hdl, const lib::error_code& ec) { void handle_accept(connection_ptr con, const lib::error_code& ec) {
lib::error_code hdl_ec;
connection_ptr con = endpoint_type::get_con_from_hdl(hdl,hdl_ec);
if (hdl_ec == error::bad_connection) {
// The connection we were trying to connect went out of scope
// This really shouldn't happen
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_accept got an invalid handle back");
//con->terminate();
} else if (hdl_ec) {
// There was some other unknown error attempting to convert the hdl
// to a connection.
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_accept error in get_con_from_hdl: "+hdl_ec.message());
//con->terminate();
} else {
if (ec) { if (ec) {
con->terminate(ec); con->terminate(ec);
@@ -121,7 +105,6 @@ public:
} else { } else {
con->start(); con->start();
} }
}
// TODO: are there cases where we should terminate this loop? // TODO: are there cases where we should terminate this loop?
start_accept(); start_accept();
@@ -1,14 +0,0 @@
Copyright (C) 1998, 2009
Paul E. Jones <paulej@packetizer.com>
Freeware Public License (FPL)
This software is licensed as "freeware." Permission to distribute
this software in source and binary forms, including incorporation
into other products, is hereby granted without a fee. THIS SOFTWARE
IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
OR DATA BEING RENDERED INACCURATE.
+185
View File
@@ -0,0 +1,185 @@
/*
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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.
*/
/*
Contributors:
Gustav
Several members in the gamedev.se forum.
Gregory Petrosyan
*/
#include "sha1.h"
namespace sha1
{
namespace // local
{
// Rotate an integer value to left.
inline const unsigned int rol(const unsigned int value,
const unsigned int steps)
{
return ((value << steps) | (value >> (32 - steps)));
}
// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
inline void clearWBuffert(unsigned int* buffert)
{
for (int pos = 16; --pos >= 0;)
{
buffert[pos] = 0;
}
}
void innerHash(unsigned int* result, unsigned int* w)
{
unsigned int a = result[0];
unsigned int b = result[1];
unsigned int c = result[2];
unsigned int d = result[3];
unsigned int e = result[4];
int round = 0;
#define sha1macro(func,val) \
{ \
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
e = d; \
d = c; \
c = rol(b, 30); \
b = a; \
a = t; \
}
while (round < 16)
{
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 20)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 40)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0x6ed9eba1)
++round;
}
while (round < 60)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
++round;
}
while (round < 80)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0xca62c1d6)
++round;
}
#undef sha1macro
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
result[4] += e;
}
} // namespace
void calc(const void* src, const int bytelength, unsigned char* hash)
{
// Init the result array.
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
// Cast the void src pointer to be the byte array we can work with.
const unsigned char* sarray = (const unsigned char*) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
const int endOfFullBlocks = bytelength - 64;
int endCurrentBlock;
int currentBlock = 0;
while (currentBlock <= endOfFullBlocks)
{
endCurrentBlock = currentBlock + 64;
// Init the round buffer with the 64 byte block data.
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
{
// This line will swap endian on big endian and keep endian on little endian.
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
| (((unsigned int) sarray[currentBlock + 2]) << 8)
| (((unsigned int) sarray[currentBlock + 1]) << 16)
| (((unsigned int) sarray[currentBlock]) << 24);
}
innerHash(result, w);
}
// Handle the last and not full 64 byte block if existing.
endCurrentBlock = bytelength - currentBlock;
clearWBuffert(w);
int lastBlockBytes = 0;
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
{
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
}
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
if (endCurrentBlock >= 56)
{
innerHash(result, w);
clearWBuffert(w);
}
w[15] = bytelength << 3;
innerHash(result, w);
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
for (int hashByte = 20; --hashByte >= 0;)
{
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
}
}
void toHexString(const unsigned char* hash, char* hexstring)
{
const char hexDigits[] = { "0123456789abcdef" };
for (int hashByte = 20; --hashByte >= 0;)
{
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
}
hexstring[40] = 0;
}
} // namespace sha1
+49
View File
@@ -0,0 +1,49 @@
/*
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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 SHA1_DEFINED
#define SHA1_DEFINED
namespace sha1
{
/**
@param src points to any kind of data to be hashed.
@param bytelength the number of bytes to hash from the src pointer.
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
*/
void calc(const void* src, const int bytelength, unsigned char* hash);
/**
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
*/
void toHexString(const unsigned char* hash, char* hexstring);
} // namespace sha1
#endif // SHA1_DEFINED
+162 -384
View File
@@ -1,406 +1,184 @@
/* /*
* sha1.hpp *****
* sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
* Copyright (C) 1998, 2009 library (http://code.google.com/p/smallsha1/) into a single header suitable for
* Paul E. Jones <paulej@packetizer.com> use as a header only library. This conversion was done by Peter Thorson
* All Rights Reserved. (webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
* under the same license as the original, which is listed below.
* Modifications were done in 2012-13 by Peter Thorson (webmaster@zaphoyd.com) *****
* to allow header only usage of the library and use C++ features to better
* support C++ usage. These changes are distributed under the original freeware Copyright (c) 2011, Micael Hildenborg
* license included below All rights reserved.
*
* Freeware Public License (FPL) Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* This software is licensed as "freeware." Permission to distribute * Redistributions of source code must retain the above copyright
* this software in source and binary forms, including incorporation notice, this list of conditions and the following disclaimer.
* into other products, is hereby granted without a fee. THIS SOFTWARE * Redistributions in binary form must reproduce the above copyright
* IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES, notice, this list of conditions and the following disclaimer in the
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY documentation and/or other materials provided with the distribution.
* AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD * Neither the name of Micael Hildenborg nor the
* LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER names of its contributors may be used to endorse or promote products
* DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA derived from this software without specific prior written permission.
* OR DATA BEING RENDERED INACCURATE.
* THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''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
* Description: DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
* This class implements the Secure Hashing Standard as defined DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* in FIPS PUB 180-1 published April 17, 1995. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* Many of the variable names in this class, especially the single ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* character names, were used because those were the names used (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* in the publication. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The Secure Hashing Standard, which uses the Secure Hashing
* Algorithm (SHA), produces a 160-bit message digest for a
* given data stream. In theory, it is highly improbable that
* two messages will produce the same message digest. Therefore,
* this algorithm can serve as a means of providing a "fingerprint"
* for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code was
* written with the expectation that the processor has at least
* a 32-bit machine word size. If the machine word size is larger,
* the code should still function properly. One caveat to that
* is that the input functions taking characters and character arrays
* assume that only 8 bits of information are stored in each character.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits long.
* Although SHA-1 allows a message digest to be generated for
* messages of any number of bits less than 2^64, this implementation
* only works with messages with a length that is a multiple of 8
* bits.
*
*****************************************************************************
*/ */
#ifndef _SHA1_H_ #ifndef SHA1_DEFINED
#define _SHA1_H_ #define SHA1_DEFINED
#include <websocketpp/common/stdint.hpp>
namespace websocketpp { namespace websocketpp {
namespace sha1 {
/// Provides SHA1 hashing functionality namespace // local
class sha1 { {
public: // Rotate an integer value to left.
sha1() { inline const unsigned int rol(const unsigned int value,
reset(); const unsigned int steps)
{
return ((value << steps) | (value >> (32 - steps)));
} }
virtual ~sha1() {} // Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
/// Re-initialize the class inline void clearWBuffert(unsigned int* buffert)
void reset() { {
length_low = 0; for (int pos = 16; --pos >= 0;)
length_high = 0; {
message_block_index = 0; buffert[pos] = 0;
}
H[0] = 0x67452301;
H[1] = 0xEFCDAB89;
H[2] = 0x98BADCFE;
H[3] = 0x10325476;
H[4] = 0xC3D2E1F0;
computed = false;
corrupted = false;
} }
/// Extract the message digest as a raw integer array inline void innerHash(unsigned int* result, unsigned int* w)
{
unsigned int a = result[0];
unsigned int b = result[1];
unsigned int c = result[2];
unsigned int d = result[3];
unsigned int e = result[4];
int round = 0;
#define sha1macro(func,val) \
{ \
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
e = d; \
d = c; \
c = rol(b, 30); \
b = a; \
a = t; \
}
while (round < 16)
{
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 20)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 40)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0x6ed9eba1)
++round;
}
while (round < 60)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
++round;
}
while (round < 80)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0xca62c1d6)
++round;
}
#undef sha1macro
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
result[4] += e;
}
} // namespace
/** /**
* @param [out] message_digest_array Integer array to store the message in @param src points to any kind of data to be hashed.
* @return Whether or not the extraction was sucessful @param bytelength the number of bytes to hash from the src pointer.
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
*/ */
bool get_raw_digest(uint32_t * message_digest_array) { inline void calc(const void* src, const int bytelength, unsigned char* hash) {
if (corrupted) { // Init the result array.
return false; unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
// Cast the void src pointer to be the byte array we can work with.
const unsigned char* sarray = (const unsigned char*) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
const int endOfFullBlocks = bytelength - 64;
int endCurrentBlock;
int currentBlock = 0;
while (currentBlock <= endOfFullBlocks)
{
endCurrentBlock = currentBlock + 64;
// Init the round buffer with the 64 byte block data.
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
{
// This line will swap endian on big endian and keep endian on little endian.
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
| (((unsigned int) sarray[currentBlock + 2]) << 8)
| (((unsigned int) sarray[currentBlock + 1]) << 16)
| (((unsigned int) sarray[currentBlock]) << 24);
}
innerHash(result, w);
} }
if (!computed) { // Handle the last and not full 64 byte block if existing.
pad_message(); endCurrentBlock = bytelength - currentBlock;
computed = true; clearWBuffert(w);
int lastBlockBytes = 0;
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
{
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
} }
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
for (int i = 0; i < 5; i++) { if (endCurrentBlock >= 56)
message_digest_array[i] = H[i]; {
innerHash(result, w);
clearWBuffert(w);
} }
w[15] = bytelength << 3;
innerHash(result, w);
return true; // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
} for (int hashByte = 20; --hashByte >= 0;)
{
/// Provide input to SHA1 hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
/**
* @param [in] message_array The input bytes
* @param [in] length Length of the message array
*/
void input(unsigned char const * message_array, uint32_t length) {
if (!length) {
return;
}
if (computed || corrupted) {
corrupted = true;
return;
}
while (length-- && !corrupted) {
// Suppresses Visual Studio code analysis for write overrun. It doesn't know the
// index into Message_Block is protected by checking length.
//
// TODO: is there a more compatible way to write the original code to avoid
// this sort of warning?
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(suppress: 6386)
#endif
message_block[message_block_index++] = (*message_array & 0xFF);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
length_low += 8;
length_low &= 0xFFFFFFFF; // Force it to 32 bits
if (length_low == 0) {
length_high++;
length_high &= 0xFFFFFFFF; // Force it to 32 bits
if (length_high == 0) {
corrupted = true; // Message is too long
} }
} }
if (message_block_index == 64) { } // namespace sha1
process_message_block();
}
message_array++;
}
}
/// Provide input to SHA1
/**
* Overload with signed message array
*
* @param [in] message_array The input bytes
* @param [in] length Length of the message array
*/
void input(char const * message_array, uint32_t length) {
input(reinterpret_cast<const unsigned char *>(message_array), length);
}
/// Provide input to SHA1
/**
* Overload with a single unsigned char
*
* @param [in] message_element The character to input
*/
void input(unsigned char message_element) {
input(&message_element, 1);
}
/// Provide input to SHA1
/**
* Overload with a single signed char
*
* @param [in] message_element The character to input
*/
void input(char message_element) {
input(reinterpret_cast<unsigned char *>(&message_element), 1);
}
/// Provide input to SHA1
/**
* Overload via signed char array stream input
*
* @param [in] message_array The character array to input
*/
sha1& operator<<(char const * message_array) {
char const * p = message_array;
while(*p) {
input(*p);
p++;
}
return *this;
}
/// Provide input to SHA1
/**
* Overload via unsigned char array stream input
*
* @param [in] message_array The character array to input
*/
sha1& operator<<(unsigned char const * message_array) {
unsigned char const * p = message_array;
while(*p) {
input(*p);
p++;
}
return *this;
}
/// Provide input to SHA1
/**
* Overload via signed char stream input
*
* @param [in] message_element The character to input
*/
sha1& operator<<(char message_element) {
input((unsigned char *) &message_element, 1);
return *this;
}
/// Provide input to SHA1
/**
* Overload via unsigned char stream input
*
* @param [in] message_element The character to input
*/
sha1& operator<<(unsigned char message_element) {
input(&message_element, 1);
return *this;
}
private:
/// Process the next 512 bits of the message
/**
* Many of the variable names in this function, especially the single
* character names, were used because those were the names used
* in the publication.
*/
void process_message_block() {
// Constants defined for SHA-1
uint32_t const K[] = { 0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6 };
uint32_t temp; // Temporary word value
uint32_t W[80]; // Word sequence
uint32_t A, B, C, D, E; // Word buffers
// Initialize the first 16 words in the array W
for (int t = 0; t < 16; t++) {
W[t] = ((uint32_t) message_block[t * 4]) << 24;
W[t] |= ((uint32_t) message_block[t * 4 + 1]) << 16;
W[t] |= ((uint32_t) message_block[t * 4 + 2]) << 8;
W[t] |= ((uint32_t) message_block[t * 4 + 3]);
}
for (int t = 16; t < 80; t++) {
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for (int t = 0; t < 20; t++) {
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for (int t = 20; t < 40; t++) {
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for (int t = 40; t < 60; t++) {
temp = CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for (int t = 60; t < 80; t++) {
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
H[0] = (H[0] + A) & 0xFFFFFFFF;
H[1] = (H[1] + B) & 0xFFFFFFFF;
H[2] = (H[2] + C) & 0xFFFFFFFF;
H[3] = (H[3] + D) & 0xFFFFFFFF;
H[4] = (H[4] + E) & 0xFFFFFFFF;
message_block_index = 0;
}
/// Pads the current message block to 512 bits
/**
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64 bits
* represent the length of the original message. All bits in between
* should be 0. This function will pad the message according to those
* rules by filling the message_block array accordingly. It will also
* call ProcessMessageBlock() appropriately. When it returns, it
* can be assumed that the message digest has been computed.
*/
void pad_message() {
// Check to see if the current message block is too small to hold
// the initial padding bits and length. If so, we will pad the
// block, process it, and then continue padding into a second block.
if (message_block_index > 55) {
message_block[message_block_index++] = 0x80;
while(message_block_index < 64) {
message_block[message_block_index++] = 0;
}
process_message_block();
while(message_block_index < 56) {
message_block[message_block_index++] = 0;
}
} else {
message_block[message_block_index++] = 0x80;
while(message_block_index < 56) {
message_block[message_block_index++] = 0;
}
}
// Store the message length as the last 8 octets
message_block[56] = (length_high >> 24) & 0xFF;
message_block[57] = (length_high >> 16) & 0xFF;
message_block[58] = (length_high >> 8) & 0xFF;
message_block[59] = (length_high) & 0xFF;
message_block[60] = (length_low >> 24) & 0xFF;
message_block[61] = (length_low >> 16) & 0xFF;
message_block[62] = (length_low >> 8) & 0xFF;
message_block[63] = (length_low) & 0xFF;
process_message_block();
}
/// Performs a circular left shift operation
/**
* @param [in] bits How many bits to shift
* @param [in] word The word to shift
* @return The shifted word
*/
inline uint32_t CircularShift(int bits, uint32_t word) {
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
}
uint32_t H[5]; // Message digest buffers
uint32_t length_low; // Message length in bits
uint32_t length_high; // Message length in bits
unsigned char message_block[64]; // 512-bit message blocks
int message_block_index; // Index into message block array
bool computed; // Is the digest computed?
bool corrupted; // Is the message digest corruped?
};
} // namespace websocketpp } // namespace websocketpp
#endif // _SHA1_H_ #endif // SHA1_DEFINED
@@ -45,6 +45,11 @@ namespace transport {
*/ */
namespace asio { namespace asio {
// Forward declaration of class endpoint so that it can be friended/referenced
// before being included.
template <typename config>
class endpoint;
typedef lib::function<void(boost::system::error_code const &)> typedef lib::function<void(boost::system::error_code const &)>
socket_shutdown_handler; socket_shutdown_handler;
@@ -81,9 +81,16 @@ public:
/// Type of a pointer to the ASIO io_service being used /// Type of a pointer to the ASIO io_service being used
typedef boost::asio::io_service* io_service_ptr; typedef boost::asio::io_service* io_service_ptr;
/// Type of a pointer to the ASIO io_service::strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
/// Type of a pointer to the ASIO timer class /// Type of a pointer to the ASIO timer class
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr; typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
// connection is friends with its associated endpoint to allow the endpoint
// to call private/protected utility methods that we don't want to expose
// to the public api.
friend class endpoint<config>;
// generate and manage our own io_service // generate and manage our own io_service
explicit connection(bool is_server, alog_type& alog, elog_type& elog) explicit connection(bool is_server, alog_type& alog, elog_type& elog)
: m_is_server(is_server) : m_is_server(is_server)
@@ -102,29 +109,13 @@ public:
return socket_con_type::is_secure(); return socket_con_type::is_secure();
} }
/// Finish constructing the transport /// Sets the tcp init handler
/** /**
* init_asio is called once immediately after construction to initialize * The tcp init handler is called after the tcp connection has been
* boost::asio components to the io_service * established.
* *
* TODO: this method is not protected because the endpoint needs to call it. * @param h The handler to call on tcp init.
* need to figure out if there is a way to friend the endpoint safely across
* different compilers.
*
* @param io_service A pointer to the io_service to register with this
* connection
*
* @return Status code for the success or failure of the initialization
*/ */
lib::error_code init_asio (io_service_ptr io_service) {
// do we need to store or use the io_service at this level?
m_io_service = io_service;
//m_strand.reset(new boost::asio::strand(*io_service));
return socket_con_type::init_asio(io_service, m_is_server);
}
void set_tcp_init_handler(tcp_init_handler h) { void set_tcp_init_handler(tcp_init_handler h) {
m_tcp_init_handler = h; m_tcp_init_handler = h;
} }
@@ -251,26 +242,6 @@ public:
return m_connection_hdl; return m_connection_hdl;
} }
/// initialize the proxy buffers and http parsers
/**
*
* @param authority The address of the server we want the proxy to tunnel to
* in the format of a URI authority (host:port)
*/
lib::error_code proxy_init(const std::string & authority) {
if (!m_proxy_data) {
return websocketpp::error::make_error_code(
websocketpp::error::invalid_state);
}
m_proxy_data->req.set_version("HTTP/1.1");
m_proxy_data->req.set_method("CONNECT");
m_proxy_data->req.set_uri(authority);
m_proxy_data->req.replace_header("Host",authority);
return lib::error_code();
}
/// Call back a function after a period of time. /// Call back a function after a period of time.
/** /**
* Sets a timer that calls back a function after the specified period of * Sets a timer that calls back a function after the specified period of
@@ -294,13 +265,13 @@ public:
); );
new_timer->async_wait( new_timer->async_wait(
lib::bind( m_strand->wrap(lib::bind(
&type::handle_timer, &type::handle_timer,
get_shared(), get_shared(),
new_timer, new_timer,
callback, callback,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
return new_timer; return new_timer;
@@ -311,10 +282,10 @@ public:
* The timer pointer is included to ensure the timer isn't destroyed until * The timer pointer is included to ensure the timer isn't destroyed until
* after it has expired. * after it has expired.
* *
* TODO: candidate for protected status
*
* @param t Pointer to the timer in question * @param t Pointer to the timer in question
*
* @param callback The function to call back * @param callback The function to call back
*
* @param ec The status code * @param ec The status code
*/ */
void handle_timer(timer_ptr t, timer_handler callback, const void handle_timer(timer_ptr t, timer_handler callback, const
@@ -332,6 +303,11 @@ public:
} }
} }
protected: protected:
/// Get a pointer to this connection's strand
strand_ptr get_strand() {
return m_strand;
}
/// Initialize transport for reading /// Initialize transport for reading
/** /**
* init_asio is called once immediately after construction to initialize * init_asio is called once immediately after construction to initialize
@@ -367,6 +343,47 @@ protected:
); );
} }
/// initialize the proxy buffers and http parsers
/**
*
* @param authority The address of the server we want the proxy to tunnel to
* in the format of a URI authority (host:port)
*
* @return Status code indicating what errors occurred, if any
*/
lib::error_code proxy_init(std::string const & authority) {
if (!m_proxy_data) {
return websocketpp::error::make_error_code(
websocketpp::error::invalid_state);
}
m_proxy_data->req.set_version("HTTP/1.1");
m_proxy_data->req.set_method("CONNECT");
m_proxy_data->req.set_uri(authority);
m_proxy_data->req.replace_header("Host",authority);
return lib::error_code();
}
/// Finish constructing the transport
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
*
* @param io_service A pointer to the io_service to register with this
* connection
*
* @return Status code for the success or failure of the initialization
*/
lib::error_code init_asio (io_service_ptr io_service) {
// do we need to store or use the io_service at this level?
m_io_service = io_service;
m_strand.reset(new boost::asio::strand(*io_service));
return socket_con_type::init_asio(io_service, m_strand, m_is_server);
}
void handle_pre_init(init_handler callback, const lib::error_code& ec) { void handle_pre_init(init_handler callback, const lib::error_code& ec) {
if (m_alog.static_test(log::alevel::devel)) { if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle pre_init"); m_alog.write(log::alevel::devel,"asio connection handle pre_init");
@@ -497,12 +514,12 @@ protected:
boost::asio::async_write( boost::asio::async_write(
socket_con_type::get_next_layer(), socket_con_type::get_next_layer(),
m_bufs, m_bufs,
lib::bind( m_strand->wrap(lib::bind(
&type::handle_proxy_write, &type::handle_proxy_write,
get_shared(), get_shared(),
callback, callback,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
@@ -568,13 +585,13 @@ protected:
socket_con_type::get_next_layer(), socket_con_type::get_next_layer(),
m_proxy_data->read_buf, m_proxy_data->read_buf,
"\r\n\r\n", "\r\n\r\n",
lib::bind( m_strand->wrap(lib::bind(
&type::handle_proxy_read, &type::handle_proxy_read,
get_shared(), get_shared(),
callback, callback,
lib::placeholders::_1, lib::placeholders::_1,
lib::placeholders::_2 lib::placeholders::_2
) ))
); );
} }
@@ -680,13 +697,13 @@ protected:
socket_con_type::get_socket(), socket_con_type::get_socket(),
boost::asio::buffer(buf,len), boost::asio::buffer(buf,len),
boost::asio::transfer_at_least(num_bytes), boost::asio::transfer_at_least(num_bytes),
lib::bind( m_strand->wrap(lib::bind(
&type::handle_async_read, &type::handle_async_read,
get_shared(), get_shared(),
handler, handler,
lib::placeholders::_1, lib::placeholders::_1,
lib::placeholders::_2 lib::placeholders::_2
) ))
); );
} }
@@ -718,12 +735,12 @@ protected:
boost::asio::async_write( boost::asio::async_write(
socket_con_type::get_socket(), socket_con_type::get_socket(),
m_bufs, m_bufs,
lib::bind( m_strand->wrap(lib::bind(
&type::handle_async_write, &type::handle_async_write,
get_shared(), get_shared(),
handler, handler,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
@@ -737,12 +754,12 @@ protected:
boost::asio::async_write( boost::asio::async_write(
socket_con_type::get_socket(), socket_con_type::get_socket(),
m_bufs, m_bufs,
lib::bind( m_strand->wrap(lib::bind(
&type::handle_async_write, &type::handle_async_write,
get_shared(), get_shared(),
handler, handler,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
@@ -773,16 +790,14 @@ protected:
/// Trigger the on_interrupt handler /// Trigger the on_interrupt handler
/** /**
* This needs to be thread safe * This needs to be thread safe
*
* Might need a strand at some point?
*/ */
lib::error_code interrupt(interrupt_handler handler) { lib::error_code interrupt(interrupt_handler handler) {
m_io_service->post(handler); m_io_service->post(m_strand->wrap(handler));
return lib::error_code(); return lib::error_code();
} }
lib::error_code dispatch(dispatch_handler handler) { lib::error_code dispatch(dispatch_handler handler) {
m_io_service->post(handler); m_io_service->post(m_strand->wrap(handler));
return lib::error_code(); return lib::error_code();
} }
@@ -905,7 +920,9 @@ private:
// transport resources // transport resources
io_service_ptr m_io_service; io_service_ptr m_io_service;
strand_ptr m_strand;
connection_hdl m_connection_hdl; connection_hdl m_connection_hdl;
std::vector<boost::asio::const_buffer> m_bufs; std::vector<boost::asio::const_buffer> m_bufs;
// Handlers // Handlers
@@ -574,13 +574,12 @@ public:
m_acceptor->async_accept( m_acceptor->async_accept(
tcon->get_raw_socket(), tcon->get_raw_socket(),
lib::bind( tcon->get_strand()->wrap(lib::bind(
&type::handle_accept, &type::handle_accept,
this, this,
tcon->get_handle(),
callback, callback,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
@@ -612,18 +611,19 @@ protected:
m_elog = e; m_elog = e;
} }
void handle_accept(connection_hdl hdl, accept_handler callback, void handle_accept(accept_handler callback, boost::system::error_code const
const boost::system::error_code& error) & boost_ec)
{ {
if (error) { lib::error_code ret_ec;
//con->terminate();
// TODO: Better translation of errors at this point m_alog->write(log::alevel::devel, "asio::handle_accept");
callback(hdl,make_error_code(error::pass_through));
return; if (boost_ec) {
log_err(log::elevel::devel,"asio handle_accept",boost_ec);
ret_ec = make_error_code(error::pass_through);
} }
//con->start(); callback(ret_ec);
callback(hdl,lib::error_code());
} }
/// Initiate a new connection /// Initiate a new connection
@@ -649,13 +649,13 @@ protected:
uri_ptr pu(new uri(proxy)); uri_ptr pu(new uri(proxy));
if (!pu->get_valid()) { if (!pu->get_valid()) {
cb(tcon->get_handle(),make_error_code(error::proxy_invalid)); cb(make_error_code(error::proxy_invalid));
return; return;
} }
ec = tcon->proxy_init(u->get_authority()); ec = tcon->proxy_init(u->get_authority());
if (ec) { if (ec) {
cb(tcon->get_handle(),ec); cb(ec);
return; return;
} }
@@ -672,12 +672,11 @@ protected:
timer_ptr dns_timer; timer_ptr dns_timer;
dns_timer = set_timer( dns_timer = tcon->set_timer(
config::timeout_dns_resolve, config::timeout_dns_resolve,
lib::bind( lib::bind(
&type::handle_resolve_timeout, &type::handle_resolve_timeout,
this, this,
tcon,
dns_timer, dns_timer,
cb, cb,
lib::placeholders::_1 lib::placeholders::_1
@@ -686,7 +685,7 @@ protected:
m_resolver->async_resolve( m_resolver->async_resolve(
query, query,
lib::bind( tcon->get_strand()->wrap(lib::bind(
&type::handle_resolve, &type::handle_resolve,
this, this,
tcon, tcon,
@@ -694,12 +693,12 @@ protected:
cb, cb,
lib::placeholders::_1, lib::placeholders::_1,
lib::placeholders::_2 lib::placeholders::_2
) ))
); );
} }
void handle_resolve_timeout(transport_con_ptr tcon, timer_ptr dns_timer, void handle_resolve_timeout(timer_ptr dns_timer, connect_handler callback,
connect_handler callback, const lib::error_code & ec) lib::error_code const & ec)
{ {
lib::error_code ret_ec; lib::error_code ret_ec;
@@ -718,11 +717,11 @@ protected:
m_alog->write(log::alevel::devel,"DNS resolution timed out"); m_alog->write(log::alevel::devel,"DNS resolution timed out");
m_resolver->cancel(); m_resolver->cancel();
callback(tcon->get_handle(),ret_ec); callback(ret_ec);
} }
void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer, void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer,
connect_handler callback, const boost::system::error_code& ec, connect_handler callback, boost::system::error_code const & ec,
boost::asio::ip::tcp::resolver::iterator iterator) boost::asio::ip::tcp::resolver::iterator iterator)
{ {
if (ec == boost::asio::error::operation_aborted || if (ec == boost::asio::error::operation_aborted ||
@@ -736,7 +735,7 @@ protected:
if (ec) { if (ec) {
log_err(log::elevel::info,"asio async_resolve",ec); log_err(log::elevel::info,"asio async_resolve",ec);
callback(tcon->get_handle(),make_error_code(error::pass_through)); callback(make_error_code(error::pass_through));
return; return;
} }
@@ -756,10 +755,10 @@ protected:
timer_ptr con_timer; timer_ptr con_timer;
con_timer = set_timer( con_timer = tcon->set_timer(
config::timeout_connect, config::timeout_connect,
lib::bind( lib::bind(
&type::handle_resolve_timeout, &type::handle_connect_timeout,
this, this,
tcon, tcon,
con_timer, con_timer,
@@ -771,19 +770,19 @@ protected:
boost::asio::async_connect( boost::asio::async_connect(
tcon->get_raw_socket(), tcon->get_raw_socket(),
iterator, iterator,
lib::bind( tcon->get_strand()->wrap(lib::bind(
&type::handle_connect, &type::handle_connect,
this, this,
tcon, tcon,
con_timer, con_timer,
callback, callback,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer, void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer,
connect_handler callback, const lib::error_code & ec) connect_handler callback, lib::error_code const & ec)
{ {
lib::error_code ret_ec; lib::error_code ret_ec;
@@ -802,11 +801,11 @@ protected:
m_alog->write(log::alevel::devel,"TCP connect timed out"); m_alog->write(log::alevel::devel,"TCP connect timed out");
tcon->cancel_socket(); tcon->cancel_socket();
callback(tcon->get_handle(),ret_ec); callback(ret_ec);
} }
void handle_connect(transport_con_ptr tcon, timer_ptr con_timer, void handle_connect(transport_con_ptr tcon, timer_ptr con_timer,
connect_handler callback, const boost::system::error_code& ec) connect_handler callback, boost::system::error_code const & ec)
{ {
if (ec == boost::asio::error::operation_aborted || if (ec == boost::asio::error::operation_aborted ||
con_timer->expires_from_now().is_negative()) con_timer->expires_from_now().is_negative())
@@ -819,7 +818,7 @@ protected:
if (ec) { if (ec) {
log_err(log::elevel::info,"asio async_connect",ec); log_err(log::elevel::info,"asio async_connect",ec);
callback(tcon->get_handle(),make_error_code(error::pass_through)); callback(make_error_code(error::pass_through));
return; return;
} }
@@ -828,7 +827,7 @@ protected:
"Async connect to "+tcon->get_remote_endpoint()+" successful."); "Async connect to "+tcon->get_remote_endpoint()+" successful.");
} }
callback(tcon->get_handle(),lib::error_code()); callback(lib::error_code());
} }
bool is_listening() const { bool is_listening() const {
@@ -58,6 +58,8 @@ public:
/// Type of a pointer to the ASIO io_service being used /// Type of a pointer to the ASIO io_service being used
typedef boost::asio::io_service* io_service_ptr; typedef boost::asio::io_service* io_service_ptr;
/// Type of a pointer to the ASIO io_service strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
/// Type of a shared pointer to the socket being used. /// Type of a shared pointer to the socket being used.
typedef lib::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr; typedef lib::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
@@ -152,7 +154,9 @@ protected:
* @param strand A shared pointer to the connection's asio strand * @param strand A shared pointer to the connection's asio strand
* @param is_server Whether or not the endpoint is a server or not. * @param is_server Whether or not the endpoint is a server or not.
*/ */
lib::error_code init_asio (io_service_ptr service, bool is_server) { lib::error_code init_asio (io_service_ptr service, strand_ptr strand,
bool is_server)
{
if (m_state != UNINITIALIZED) { if (m_state != UNINITIALIZED) {
return socket::make_error_code(socket::error::invalid_state); return socket::make_error_code(socket::error::invalid_state);
} }
@@ -68,6 +68,8 @@ public:
typedef lib::shared_ptr<socket_type> socket_ptr; typedef lib::shared_ptr<socket_type> socket_ptr;
/// Type of a pointer to the ASIO io_service being used /// Type of a pointer to the ASIO io_service being used
typedef boost::asio::io_service* io_service_ptr; typedef boost::asio::io_service* io_service_ptr;
/// Type of a pointer to the ASIO io_service strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
/// Type of a shared pointer to the ASIO TLS context being used /// Type of a shared pointer to the ASIO TLS context being used
typedef lib::shared_ptr<boost::asio::ssl::context> context_ptr; typedef lib::shared_ptr<boost::asio::ssl::context> context_ptr;
@@ -174,9 +176,12 @@ protected:
* boost::asio components to the io_service * boost::asio components to the io_service
* *
* @param service A pointer to the endpoint's io_service * @param service A pointer to the endpoint's io_service
* @param strand A pointer to the connection's strand
* @param is_server Whether or not the endpoint is a server or not. * @param is_server Whether or not the endpoint is a server or not.
*/ */
lib::error_code init_asio (io_service_ptr service, bool is_server) { lib::error_code init_asio (io_service_ptr service, strand_ptr strand,
bool is_server)
{
if (!m_tls_init_handler) { if (!m_tls_init_handler) {
return socket::make_error_code(socket::error::missing_tls_init_handler); return socket::make_error_code(socket::error::missing_tls_init_handler);
} }
@@ -188,6 +193,7 @@ protected:
m_socket.reset(new socket_type(*service,*m_context)); m_socket.reset(new socket_type(*service,*m_context));
m_io_service = service; m_io_service = service;
m_strand = strand;
m_is_server = is_server; m_is_server = is_server;
return lib::error_code(); return lib::error_code();
@@ -224,12 +230,12 @@ protected:
// TLS handshake // TLS handshake
m_socket->async_handshake( m_socket->async_handshake(
get_handshake_type(), get_handshake_type(),
lib::bind( m_strand->wrap(lib::bind(
&type::handle_init, &type::handle_init,
get_shared(), get_shared(),
callback, callback,
lib::placeholders::_1 lib::placeholders::_1
) ))
); );
} }
@@ -278,6 +284,7 @@ private:
} }
io_service_ptr m_io_service; io_service_ptr m_io_service;
strand_ptr m_strand;
context_ptr m_context; context_ptr m_context;
socket_ptr m_socket; socket_ptr m_socket;
bool m_is_server; bool m_is_server;
@@ -71,12 +71,10 @@ namespace websocketpp {
namespace transport { namespace transport {
/// The type and signature of the callback passed to the accept method /// The type and signature of the callback passed to the accept method
typedef lib::function<void(connection_hdl, lib::error_code const &)> typedef lib::function<void(lib::error_code const &)> accept_handler;
accept_handler;
/// The type and signature of the callback passed to the connect method /// The type and signature of the callback passed to the connect method
typedef lib::function<void(connection_hdl, lib::error_code const &)> typedef lib::function<void(lib::error_code const &)> connect_handler;
connect_handler;
} // namespace transport } // namespace transport
} // namespace websocketpp } // namespace websocketpp
@@ -141,7 +141,7 @@ protected:
* @param cb The function to call back with the results when complete. * @param cb The function to call back with the results when complete.
*/ */
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
cb(tcon->get_handle(),lib::error_code()); cb(lib::error_code());
} }
/// Initialize a connection /// Initialize a connection
+4 -1
View File
@@ -138,7 +138,10 @@ public:
std::string port = ""; std::string port = "";
while (state == 1) { while (state == 1) {
if (it == uri.end()) { if (it == uri.end()) {
state = 3; // state is not used after this point presently.
// this should be re-enabled if it ever is needed in a future
// refactoring
//state = 3;
break; break;
} else if (*it == '/') { } else if (*it == '/') {
state = 3; state = 3;
+27 -2
View File
@@ -1,5 +1,30 @@
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> /*
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. * The following code is adapted from code originally written by Bjoern
* Hoehrmann <bjoern@hoehrmann.de>. See
* http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
*
* The original license:
*
* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef UTF8_VALIDATOR_HPP #ifndef UTF8_VALIDATOR_HPP
#define UTF8_VALIDATOR_HPP #define UTF8_VALIDATOR_HPP
+2 -2
View File
@@ -50,10 +50,10 @@ static int const patch_version = 0;
* This is a textual flag indicating the type and number for pre-release * This is a textual flag indicating the type and number for pre-release
* versions (dev, alpha, beta, rc). This will be blank for release versions. * versions (dev, alpha, beta, rc). This will be blank for release versions.
*/ */
static char const prerelease_flag[] = "alpha3"; static char const prerelease_flag[] = "alpha4";
/// Default user agent string /// Default user agent string
static char const user_agent[] = "WebSocket++/0.3.0-alpha3"; static char const user_agent[] = "WebSocket++/0.3.0-alpha4";
} // namespace websocketpp } // namespace websocketpp