mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
lots of misc fixes, mostly broadcast server related
This commit is contained in:
5
Makefile
5
Makefile
@@ -28,7 +28,7 @@
|
||||
# It's authors were Jonathan Wallace and Bernhard Fluehmann.
|
||||
|
||||
|
||||
objects = network_utilities.o sha1.o base64.o md5.o uri.o hybi_header.o
|
||||
objects = network_utilities.o sha1.o base64.o md5.o uri.o hybi_header.o data.o
|
||||
|
||||
BOOST_LIB_PATH ?= /usr/local/lib
|
||||
BOOST_INCLUDE_PATH ?= /usr/local/include
|
||||
@@ -148,6 +148,9 @@ $(objdir)/base64.o: $(srcdir)/base64/base64.cpp
|
||||
$(objdir)/hybi_header.o: $(srcdir)/processors/hybi_header.cpp
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
$(objdir)/data.o: $(srcdir)/messages/data.cpp
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
$(objdir)/md5.o: $(srcdir)/md5/md5.c
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
<script type="text/javascript">
|
||||
var options = {"console_enabled": true};
|
||||
|
||||
var ws;
|
||||
var ws_client;
|
||||
var ws_admin;
|
||||
var url;
|
||||
|
||||
var data2 = [], total_points = 240;
|
||||
@@ -26,34 +27,58 @@ var msgs = {};
|
||||
|
||||
function connect() {
|
||||
url = document.getElementById("server_url").value;
|
||||
console.log(url);
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
ws_client = new WebSocket(url);
|
||||
ws_admin = new WebSocket(url+"/admin");
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
ws_client = new MozWebSocket(url);
|
||||
ws_admin = new MozWebSocket(url+"/admin");
|
||||
} else {
|
||||
document.getElementById("messages").innerHTML += "This Browser does not support WebSockets<br />";
|
||||
$("#messages").innerHTML += "This Browser does not support WebSockets<br />";
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: A connection to "+ws.URL+" has been opened.<br />";
|
||||
|
||||
ws_client.onopen = function(e) {
|
||||
$("#messages").append("Client: A client connection to "+url+" has been opened.<br />");
|
||||
|
||||
document.getElementById("server_url").disabled = true;
|
||||
document.getElementById("toggle_connect").innerHTML = "Disconnect";
|
||||
$("#server_url").disabled = true;
|
||||
$("#toggle_connect").html("Disconnect");
|
||||
};
|
||||
|
||||
ws_admin.onopen = function(e) {
|
||||
$("#messages").append("Client: An admin connection to "+url+"/admin has been opened.<br />");
|
||||
|
||||
$("#server_url").disabled = true;
|
||||
$("#toggle_connect").html("Disconnect");
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: An error occured, see console log for more details.<br />";
|
||||
ws_client.onerror = function(e) {
|
||||
$("#messages").append("Client: An error occured on the client channel, see console log for more details.<br />");
|
||||
console.log(e);
|
||||
};
|
||||
ws_admin.onerror = function(e) {
|
||||
$("#messages").append("Client: An error occured on the admin channel, see console log for more details.<br />");
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: The connection to "+url+" was closed.<br />";
|
||||
ws_client.onclose = function(e) {
|
||||
$("#messages").append("Client: The client connection to "+url+" was closed.<br />");
|
||||
clear_hud();
|
||||
};
|
||||
|
||||
ws_admin.onclose = function(e) {
|
||||
$("#messages").append("Client: The admin connection to "+url+"/admin was closed.<br />");
|
||||
clear_hud();
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
ws_client.onmessage = function(e) {
|
||||
if (options.console_enabled) {
|
||||
$("#messages").append("Broadcasted Message: "+e.data+"<br />");
|
||||
}
|
||||
}
|
||||
|
||||
ws_admin.onmessage = function(e) {
|
||||
foo = JSON.parse(e.data);
|
||||
|
||||
if (foo.type == "message") {
|
||||
@@ -143,7 +168,8 @@ function clear_hud() {
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
ws_client.close();
|
||||
ws_admin.close();
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
@@ -154,20 +180,20 @@ function toggle_connect() {
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (ws === undefined || ws.readyState != 1) {
|
||||
document.getElementById("messages").innerHTML += "Client: Websocket is not avaliable for writing<br />";
|
||||
function broadcast() {
|
||||
if (ws_client === undefined || ws_client.readyState != 1) {
|
||||
$("#messages").append("Client: Client websocket is not avaliable for writing<br />");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send(document.getElementById("msg").value);
|
||||
ws_client.send(document.getElementById("msg").value);
|
||||
document.getElementById("msg").value = "";
|
||||
}
|
||||
|
||||
function send_command(command,args) {
|
||||
var cmd = command+":";
|
||||
|
||||
ws.send(cmd);
|
||||
ws_admin.send(cmd);
|
||||
}
|
||||
|
||||
function send_test_message(size,type) {
|
||||
@@ -277,12 +303,12 @@ body,html {
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9002/admin" />
|
||||
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9002" />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
|
||||
<button onclick="send();">Broadcast</button></div>
|
||||
<button onclick="broadcast();">Broadcast</button></div>
|
||||
|
||||
<h2>Stats</h2>
|
||||
<h3>Server</h3>
|
||||
|
||||
190
examples/broadcast_server_tls/broadcast_admin_handler.hpp
Normal file
190
examples/broadcast_server_tls/broadcast_admin_handler.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. 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 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
|
||||
* 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;
|
||||
* 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 WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|
||||
#define WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|
||||
|
||||
#include "../../src/endpoint.hpp"
|
||||
#include "../../src/roles/server.hpp"
|
||||
#include "../../src/sockets/ssl.hpp"
|
||||
|
||||
#include "broadcast_handler.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace broadcast {
|
||||
|
||||
template <typename endpoint_type>
|
||||
class admin_handler : public endpoint_type::handler {
|
||||
public:
|
||||
typedef admin_handler<endpoint_type> type;
|
||||
typedef boost::shared_ptr<type> ptr;
|
||||
typedef typename endpoint_type::handler_ptr handler_ptr;
|
||||
typedef typename handler<endpoint_type>::ptr broadcast_handler_ptr;
|
||||
typedef typename endpoint_type::connection_ptr connection_ptr;
|
||||
|
||||
admin_handler()
|
||||
: m_epoch(boost::posix_time::time_from_string("1970-01-01 00:00:00.000"))
|
||||
{}
|
||||
|
||||
void on_open(connection_ptr connection) {
|
||||
if (!m_timer) {
|
||||
m_timer.reset(new boost::asio::deadline_timer(connection->get_io_service(),boost::posix_time::seconds(0)));
|
||||
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
||||
m_timer->async_wait(boost::bind(&type::on_timer,this,boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
m_connections.insert(connection);
|
||||
}
|
||||
|
||||
// this dummy tls init function will cause all TLS connections to fail.
|
||||
// TLS handling for broadcast::handler is usually done by a lobby handler.
|
||||
// If you want to use the broadcast handler alone with TLS then return the
|
||||
// appropriately filled in context here.
|
||||
boost::shared_ptr<boost::asio::ssl::context> on_tls_init() {
|
||||
return boost::shared_ptr<boost::asio::ssl::context>();
|
||||
}
|
||||
|
||||
void on_load(connection_ptr connection, handler_ptr old_handler) {
|
||||
this->on_open(connection);
|
||||
m_lobby = old_handler;
|
||||
}
|
||||
|
||||
void track(broadcast_handler_ptr target) {
|
||||
m_broadcast_handler = target;
|
||||
}
|
||||
|
||||
void on_close(connection_ptr connection) {
|
||||
m_connections.erase(connection);
|
||||
}
|
||||
|
||||
void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
wscmd::cmd command = wscmd::parse(msg->get_payload());
|
||||
|
||||
if (command.command == "close") {
|
||||
handle_close(connection,command);
|
||||
} else {
|
||||
command_error(connection,"Invalid Command");
|
||||
}
|
||||
|
||||
connection->recycle(msg);
|
||||
}
|
||||
|
||||
void command_error(connection_ptr connection,const std::string msg) {
|
||||
connection->send("{\"type\":\"error\",\"value\":\""+msg+"\"}");
|
||||
}
|
||||
|
||||
// close: - close this connection
|
||||
// close:all; close all connections
|
||||
void handle_close(connection_ptr connection,const wscmd::cmd& command) {
|
||||
if (!m_broadcast_handler) {
|
||||
// Unable to connect to local broadcast handler
|
||||
return;
|
||||
}
|
||||
|
||||
m_broadcast_handler->close_connection(connection_ptr());
|
||||
}
|
||||
|
||||
long get_ms(boost::posix_time::ptime s) const {
|
||||
boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
|
||||
boost::posix_time::time_period period(s,now);
|
||||
return period.length().total_milliseconds();
|
||||
}
|
||||
|
||||
void on_timer(const boost::system::error_code& error) {
|
||||
if (!m_broadcast_handler) {
|
||||
// Unable to connect to local broadcast handler
|
||||
return;
|
||||
}
|
||||
|
||||
long milli_seconds = get_ms(m_epoch);
|
||||
|
||||
std::stringstream update;
|
||||
update << "{\"type\":\"stats\""
|
||||
<< ",\"timestamp\":" << milli_seconds
|
||||
<< ",\"connections\":" << m_broadcast_handler->get_connection_count()
|
||||
<< ",\"admin_connections\":" << m_connections.size()
|
||||
<< ",\"messages\":[";
|
||||
|
||||
const msg_map& m = m_broadcast_handler->get_message_stats();
|
||||
|
||||
msg_map::const_iterator msg_it;
|
||||
msg_map::const_iterator last = m.end();
|
||||
if (m.size() > 0) {
|
||||
last--;
|
||||
}
|
||||
|
||||
for (msg_it = m.begin(); msg_it != m.end(); msg_it++) {
|
||||
update << "{\"id\":" << (*msg_it).second.id
|
||||
<< ",\"hash\":\"" << (*msg_it).second.hash << "\""
|
||||
<< ",\"sent\":" << (*msg_it).second.sent
|
||||
<< ",\"acked\":" << (*msg_it).second.acked
|
||||
<< ",\"size\":" << (*msg_it).second.size
|
||||
<< ",\"time\":" << (*msg_it).second.time
|
||||
<< "}" << (msg_it == last ? "" : ",");
|
||||
}
|
||||
|
||||
update << "]}";
|
||||
|
||||
m_broadcast_handler->clear_message_stats();
|
||||
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
(*it)->send(update.str(),false);
|
||||
}
|
||||
|
||||
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
||||
m_timer->async_wait(
|
||||
boost::bind(
|
||||
&type::on_timer,
|
||||
this,
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
private:
|
||||
handler_ptr m_lobby;
|
||||
broadcast_handler_ptr m_broadcast_handler;
|
||||
|
||||
std::set<connection_ptr> m_connections;
|
||||
boost::posix_time::ptime m_epoch;
|
||||
|
||||
boost::shared_ptr<boost::asio::deadline_timer> m_timer;
|
||||
};
|
||||
|
||||
} // namespace broadcast
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|
||||
201
examples/broadcast_server_tls/broadcast_handler.hpp
Normal file
201
examples/broadcast_server_tls/broadcast_handler.hpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. 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 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
|
||||
* 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;
|
||||
* 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 WEBSOCKETPP_BROADCAST_HANDLER_HPP
|
||||
#define WEBSOCKETPP_BROADCAST_HANDLER_HPP
|
||||
|
||||
#include "wscmd.hpp"
|
||||
|
||||
#include "../../src/endpoint.hpp"
|
||||
#include "../../src/roles/server.hpp"
|
||||
#include "../../src/sockets/ssl.hpp"
|
||||
|
||||
#include "../../src/md5/md5.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace broadcast {
|
||||
|
||||
/// this structure is used to keep track of message statistics
|
||||
struct msg {
|
||||
int id;
|
||||
size_t sent;
|
||||
size_t acked;
|
||||
size_t size;
|
||||
uint64_t time;
|
||||
|
||||
std::string hash;
|
||||
boost::posix_time::ptime time_sent;
|
||||
};
|
||||
|
||||
typedef std::map<std::string,struct msg> msg_map;
|
||||
|
||||
template <typename endpoint_type>
|
||||
class handler : public endpoint_type::handler {
|
||||
public:
|
||||
typedef handler<endpoint_type> type;
|
||||
typedef boost::shared_ptr<type> ptr;
|
||||
typedef typename endpoint_type::handler_ptr handler_ptr;
|
||||
typedef typename endpoint_type::connection_ptr connection_ptr;
|
||||
|
||||
handler() : m_nextid(0) {}
|
||||
|
||||
void on_open(connection_ptr connection) {
|
||||
m_connections.insert(connection);
|
||||
}
|
||||
|
||||
// this dummy tls init function will cause all TLS connections to fail.
|
||||
// TLS handling for broadcast::handler is usually done by a lobby handler.
|
||||
// If you want to use the broadcast handler alone with TLS then return the
|
||||
// appropriately filled in context here.
|
||||
boost::shared_ptr<boost::asio::ssl::context> on_tls_init() {
|
||||
return boost::shared_ptr<boost::asio::ssl::context>();
|
||||
}
|
||||
|
||||
void on_load(connection_ptr connection, handler_ptr old_handler) {
|
||||
this->on_open(connection);
|
||||
m_lobby = old_handler;
|
||||
}
|
||||
|
||||
void on_close(connection_ptr connection) {
|
||||
m_connections.erase(connection);
|
||||
}
|
||||
|
||||
void on_message(connection_ptr connection,message::data_ptr msg) {
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
wscmd::cmd command = wscmd::parse(msg->get_payload());
|
||||
|
||||
if (command.command == "ack") {
|
||||
handle_ack(connection,command);
|
||||
} else {
|
||||
broadcast_message(msg);
|
||||
}
|
||||
|
||||
connection->recycle(msg);
|
||||
}
|
||||
|
||||
void command_error(connection_ptr connection,const std::string msg) {
|
||||
connection->send("{\"type\":\"error\",\"value\":\""+msg+"\"}");
|
||||
}
|
||||
|
||||
// ack:e3458d0aceff8b70a3e5c0afec632881=38;e3458d0aceff8b70a3e5c0afec632881=42;
|
||||
void handle_ack(connection_ptr connection,const wscmd::cmd& command) {
|
||||
wscmd::arg_list::const_iterator arg_it;
|
||||
size_t count;
|
||||
|
||||
for (arg_it = command.args.begin(); arg_it != command.args.end(); arg_it++) {
|
||||
if (m_msgs.find(arg_it->first) == m_msgs.end()) {
|
||||
std::cout << "ack for message we didn't send" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
count = atol(arg_it->second.c_str());
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct msg& m(m_msgs[arg_it->first]);
|
||||
|
||||
m.acked += count;
|
||||
|
||||
if (m.acked == m.sent) {
|
||||
m.time = get_ms(m.time_sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close: - close this connection
|
||||
// close:all; close all connections
|
||||
void close_connection(connection_ptr connection) {
|
||||
if (connection){
|
||||
connection->close(close::status::NORMAL);
|
||||
} else {
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
|
||||
(*it)->close(close::status::NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void broadcast_message(message::data_ptr msg) {
|
||||
std::string hash = md5_hash_hex(msg->get_payload());
|
||||
struct msg& new_msg(m_msgs[hash]);
|
||||
|
||||
new_msg.id = m_nextid++;
|
||||
new_msg.hash = hash;
|
||||
new_msg.size = msg->get_payload().size();
|
||||
new_msg.time_sent = boost::posix_time::microsec_clock::local_time();
|
||||
new_msg.time = 0;
|
||||
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
// broadcast to clients
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
(*it)->send(msg->get_payload(),(msg->get_opcode() == frame::opcode::BINARY));
|
||||
}
|
||||
new_msg.sent = m_connections.size();
|
||||
new_msg.acked = 0;
|
||||
}
|
||||
|
||||
long get_ms(boost::posix_time::ptime s) const {
|
||||
boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
|
||||
boost::posix_time::time_period period(s,now);
|
||||
return period.length().total_milliseconds();
|
||||
}
|
||||
|
||||
// hooks for admin console
|
||||
size_t get_connection_count() const {
|
||||
return m_connections.size();
|
||||
}
|
||||
|
||||
const msg_map& get_message_stats() const {
|
||||
return m_msgs;
|
||||
}
|
||||
|
||||
void clear_message_stats() {
|
||||
m_msgs.empty();
|
||||
}
|
||||
private:
|
||||
handler_ptr m_lobby;
|
||||
|
||||
int m_nextid;
|
||||
msg_map m_msgs;
|
||||
|
||||
std::set<connection_ptr> m_connections;
|
||||
};
|
||||
|
||||
} // namespace broadcast
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_BROADCAST_HANDLER_HPP
|
||||
142
examples/broadcast_server_tls/broadcast_server_handler.hpp
Normal file
142
examples/broadcast_server_tls/broadcast_server_handler.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. 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 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
|
||||
* 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;
|
||||
* 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 WEBSOCKETPP_BROADCAST_SERVER_HANDLER_HPP
|
||||
#define WEBSOCKETPP_BROADCAST_SERVER_HANDLER_HPP
|
||||
|
||||
#include "../../src/endpoint.hpp"
|
||||
#include "../../src/roles/server.hpp"
|
||||
#include "../../src/sockets/ssl.hpp"
|
||||
|
||||
#include "broadcast_handler.hpp"
|
||||
#include "broadcast_admin_handler.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace broadcast {
|
||||
|
||||
template <typename endpoint_type>
|
||||
class server_handler : public endpoint_type::handler {
|
||||
public:
|
||||
typedef server_handler<endpoint_type> type;
|
||||
typedef boost::shared_ptr<type> ptr;
|
||||
typedef typename endpoint_type::handler_ptr handler_ptr;
|
||||
typedef typename admin_handler<endpoint_type>::ptr admin_handler_ptr;
|
||||
typedef typename handler<endpoint_type>::ptr broadcast_handler_ptr;
|
||||
typedef typename endpoint_type::connection_ptr connection_ptr;
|
||||
|
||||
server_handler();
|
||||
|
||||
std::string get_password() const {
|
||||
return "test";
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::ssl::context> on_tls_init() {
|
||||
// create a tls context, init, and return.
|
||||
boost::shared_ptr<boost::asio::ssl::context> context(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
|
||||
try {
|
||||
context->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
context->set_password_callback(boost::bind(&type::get_password, this));
|
||||
context->use_certificate_chain_file("../../src/ssl/server.pem");
|
||||
context->use_private_key_file("../../src/ssl/server.pem", boost::asio::ssl::context::pem);
|
||||
context->use_tmp_dh_file("../../src/ssl/dh512.pem");
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
void validate(connection_ptr connection) {}
|
||||
|
||||
void on_open(connection_ptr connection) {
|
||||
if (connection->get_resource() == "/admin") {
|
||||
connection->set_handler(m_admin_handler);
|
||||
} else {
|
||||
connection->set_handler(m_broadcast_handler);
|
||||
}
|
||||
}
|
||||
|
||||
void on_unload(connection_ptr connection, handler_ptr new_handler) {
|
||||
|
||||
}
|
||||
|
||||
void on_close(connection_ptr connection) {}
|
||||
|
||||
void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {}
|
||||
|
||||
void http(connection_ptr connection);
|
||||
|
||||
void on_fail(connection_ptr connection) {
|
||||
std::cout << "connection failed" << std::endl;
|
||||
}
|
||||
|
||||
// utility
|
||||
|
||||
handler_ptr get_broadcast_handler() {
|
||||
return m_broadcast_handler;
|
||||
}
|
||||
|
||||
private:
|
||||
admin_handler_ptr m_admin_handler;
|
||||
broadcast_handler_ptr m_broadcast_handler;
|
||||
};
|
||||
|
||||
} // namespace broadcast
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
|
||||
|
||||
namespace websocketpp {
|
||||
namespace broadcast {
|
||||
|
||||
template <class endpoint>
|
||||
server_handler<endpoint>::server_handler()
|
||||
: m_admin_handler(new admin_handler<endpoint>()),
|
||||
m_broadcast_handler(new handler<endpoint>())
|
||||
{
|
||||
m_admin_handler->track(m_broadcast_handler);
|
||||
}
|
||||
|
||||
template <class endpoint>
|
||||
void server_handler<endpoint>::http(connection_ptr connection) {
|
||||
std::stringstream foo;
|
||||
|
||||
foo << "<html><body><p>"
|
||||
<< m_broadcast_handler->get_connection_count()
|
||||
<< " current connections.</p></body></html>";
|
||||
|
||||
connection->set_body(foo.str());
|
||||
}
|
||||
|
||||
} // namespace broadcast
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_BROADCAST_SERVER_HANDLER_HPP
|
||||
@@ -28,7 +28,8 @@
|
||||
#include "../../src/endpoint.hpp"
|
||||
#include "../../src/roles/server.hpp"
|
||||
#include "../../src/sockets/ssl.hpp"
|
||||
#include "../../src/md5/md5.hpp"
|
||||
|
||||
#include "broadcast_server_handler.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
@@ -37,460 +38,12 @@
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
struct msg {
|
||||
int id;
|
||||
size_t sent;
|
||||
size_t acked;
|
||||
size_t size;
|
||||
uint64_t time;
|
||||
|
||||
std::string hash;
|
||||
boost::posix_time::ptime time_sent;
|
||||
|
||||
};
|
||||
|
||||
typedef websocketpp::endpoint<websocketpp::role::server,websocketpp::socket::plain> plain_endpoint_type;
|
||||
typedef plain_endpoint_type::handler_ptr plain_handler_ptr;
|
||||
|
||||
typedef websocketpp::endpoint<websocketpp::role::server,websocketpp::socket::ssl> tls_endpoint_type;
|
||||
typedef tls_endpoint_type::handler_ptr tls_handler_ptr;
|
||||
|
||||
template <typename endpoint_type>
|
||||
class broadcast_server_handler : public endpoint_type::handler {
|
||||
public:
|
||||
typedef broadcast_server_handler<endpoint_type> type;
|
||||
typedef typename endpoint_type::connection_ptr connection_ptr;
|
||||
|
||||
broadcast_server_handler()
|
||||
: m_epoch(boost::posix_time::time_from_string("1970-01-01 00:00:00.000")),
|
||||
m_nextid(0)
|
||||
{
|
||||
m_messages = 0;
|
||||
m_data = 0;
|
||||
}
|
||||
|
||||
std::string get_password() const {
|
||||
return "test";
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::ssl::context> on_tls_init() {
|
||||
// create a tls context, init, and return.
|
||||
boost::shared_ptr<boost::asio::ssl::context> context(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
|
||||
try {
|
||||
context->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
context->set_password_callback(boost::bind(&type::get_password, this));
|
||||
context->use_certificate_chain_file("../../src/ssl/server.pem");
|
||||
context->use_private_key_file("../../src/ssl/server.pem", boost::asio::ssl::context::pem);
|
||||
context->use_tmp_dh_file("../../src/ssl/dh512.pem");
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
void validate(connection_ptr connection) {
|
||||
//std::cout << "state: " << connection->get_state() << std::endl;
|
||||
}
|
||||
|
||||
void on_open(connection_ptr connection) {
|
||||
if (!m_timer) {
|
||||
m_timer.reset(new boost::asio::deadline_timer(connection->get_io_service(),boost::posix_time::seconds(0)));
|
||||
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
||||
m_timer->async_wait(boost::bind(&type::on_timer,this,boost::asio::placeholders::error));
|
||||
m_last_time = boost::posix_time::microsec_clock::local_time();
|
||||
}
|
||||
|
||||
if (connection->get_resource() == "/admin") {
|
||||
m_admin_connections.insert(connection);
|
||||
} else {
|
||||
m_connections.insert(connection);
|
||||
}
|
||||
|
||||
/*typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
std::stringstream foo;
|
||||
foo << "{\"type\":\"con\""
|
||||
<< ",\"timestamp\":" << get_ms(m_epoch)
|
||||
<< ",\"value\":" << m_connections.size()
|
||||
<< "}";
|
||||
|
||||
for (it = m_admin_connections.begin(); it != m_admin_connections.end(); it++) {
|
||||
(*it)->send(foo.str(),false);
|
||||
}*/
|
||||
}
|
||||
|
||||
void on_close(connection_ptr connection) {
|
||||
//std::cout << "connection closed" << std::endl;
|
||||
m_connections.erase(connection);
|
||||
m_admin_connections.erase(connection);
|
||||
|
||||
/*typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
std::stringstream foo;
|
||||
foo << "{\"type\":\"con\""
|
||||
<< ",\"timestamp\":" << get_ms(m_epoch)
|
||||
<< ",\"value\":" << m_connections.size()
|
||||
<< "}";
|
||||
|
||||
for (it = m_admin_connections.begin(); it != m_admin_connections.end(); it++) {
|
||||
(*it)->send(foo.str(),false);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
|
||||
// command structure
|
||||
// command:arg1=val1;arg2=val2;arg3=val3;
|
||||
|
||||
// commands
|
||||
// ack: messages to ack
|
||||
// example: `ack:e3458d0aceff8b70a3e5c0afec632881=38;e3458d0aceff8b70a3e5c0afec632881=42;`
|
||||
|
||||
// send: [vals]
|
||||
// message; opcode=X; payload="X"
|
||||
// frame; [fuzzer stuff]
|
||||
|
||||
// close:code=1000;reason=msg;
|
||||
// (instructs the opposite end to close with given optional code/msg)
|
||||
|
||||
const std::string &m(msg->get_payload());
|
||||
|
||||
std::string::size_type start;
|
||||
std::string::size_type end;
|
||||
|
||||
start = m.find(":",0);
|
||||
|
||||
if (start != std::string::npos) {
|
||||
std::string command = m.substr(0,start);
|
||||
|
||||
// parse args
|
||||
std::map<std::string,std::string> args;
|
||||
|
||||
start++; // skip the colon
|
||||
end = m.find(";",start);
|
||||
|
||||
// find all semicolons
|
||||
while (end != std::string::npos) {
|
||||
std::string arg;
|
||||
std::string val;
|
||||
|
||||
std::string::size_type sep = m.find("=",start);
|
||||
|
||||
if (sep != std::string::npos) {
|
||||
arg = m.substr(start,sep-start);
|
||||
val = m.substr(sep+1,end-sep-1);
|
||||
} else {
|
||||
arg = m.substr(start,end-start);
|
||||
val = "";
|
||||
}
|
||||
|
||||
args[arg] = val;
|
||||
|
||||
start = end+1;
|
||||
end = m.find(";",start);
|
||||
}
|
||||
|
||||
if (command == "close") {
|
||||
handle_close(connection,args);
|
||||
} else if (command == "send") {
|
||||
handle_send(connection,args);
|
||||
} else {
|
||||
command_error(connection,"Unrecognized command: "+command);
|
||||
}
|
||||
} else {
|
||||
command_error(connection,"Invalid command syntax");
|
||||
}
|
||||
|
||||
if (msg->get_payload().substr(0,27) == "{\"type\":\"acks\",\"messages\":[") {
|
||||
//std::cout << "got ack" << std::endl;
|
||||
//std::cout << msg->get_payload() << std::endl;
|
||||
// process a
|
||||
//
|
||||
|
||||
//{"type":"acks","messages":[{"e3458d0aceff8b70a3e5c0afec632881":38},{"e3458d0aceff8b70a3e5c0afec632881":38}]}
|
||||
|
||||
std::string::size_type start = 27;
|
||||
std::string::size_type end = msg->get_payload().find(",",start);
|
||||
size_t count;
|
||||
|
||||
m_messages_acked = 0;
|
||||
|
||||
while (end != std::string::npos) {
|
||||
if (end-start < 38) {
|
||||
// error, not the input we were expecting
|
||||
continue;
|
||||
} else {
|
||||
count = atol(msg->get_payload().substr(start+36,end-2).c_str());
|
||||
if (count == 0) {
|
||||
// error parsing number
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
std::string hash = msg->get_payload().substr(start+2,32);
|
||||
|
||||
std::map<std::string,struct msg>::iterator it = m_msgs.find(hash);
|
||||
if (it == m_msgs.end()) {
|
||||
std::cout << "ack for message we didn't send" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct msg& m(m_msgs[hash]);
|
||||
|
||||
m.acked += count;
|
||||
|
||||
if (m.acked == m.sent) {
|
||||
m.time = get_ms(m.time_sent);
|
||||
}
|
||||
|
||||
start = end+1;
|
||||
end = msg->get_payload().find(",",start);
|
||||
}
|
||||
|
||||
end = msg->get_payload().size();
|
||||
|
||||
// get the last value
|
||||
if (end-start < 38) {
|
||||
// error, not the input we were expecting
|
||||
return;
|
||||
} else {
|
||||
count = atol(msg->get_payload().substr(start+36,end-4).c_str());
|
||||
if (count == 0) {
|
||||
// error parsing number
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string hash = msg->get_payload().substr(start+2,32);
|
||||
|
||||
std::map<std::string,struct msg>::iterator it = m_msgs.find(hash);
|
||||
if (it == m_msgs.end()) {
|
||||
std::cout << "ack for message we didn't send: " << hash
|
||||
<< "(" << hash.size() << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
struct msg& m(m_msgs[msg->get_payload().substr(start+2,32)]);
|
||||
|
||||
m.acked += count;
|
||||
|
||||
if (m.acked == m.sent) {
|
||||
m.time = get_ms(m.time_sent);
|
||||
}
|
||||
|
||||
//m_ack_stats[msg->get_payload().substr(start+2,32)] = count;
|
||||
// m_messages_acked += count;
|
||||
} else {
|
||||
std::string hash = websocketpp::md5_hash_hex(msg->get_payload());
|
||||
struct msg& new_msg(m_msgs[hash]);
|
||||
|
||||
new_msg.id = m_nextid++;
|
||||
new_msg.hash = hash;
|
||||
new_msg.size = msg->get_payload().size();
|
||||
new_msg.time_sent = boost::posix_time::microsec_clock::local_time();
|
||||
new_msg.time = 0;
|
||||
|
||||
// broadcast to clients
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
//std::cout << "sending message: (" << hash.size() << ") " << hash << std::endl;
|
||||
m_messages++;
|
||||
m_data += msg->get_payload().size();
|
||||
(*it)->send(msg->get_payload(),(msg->get_opcode() == websocketpp::frame::opcode::BINARY));
|
||||
}
|
||||
new_msg.sent = m_connections.size();
|
||||
new_msg.acked = 0;
|
||||
|
||||
// broadcast to admins
|
||||
std::stringstream foo;
|
||||
foo << "{\"type\":\"message\",\"value\":\"";
|
||||
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::BINARY) {
|
||||
foo << "[Binary Message, length: " << msg->get_payload().size() << "]";
|
||||
} else {
|
||||
if (msg->get_payload().size() > 126) {
|
||||
foo << "[UTF8 Message, length: " << msg->get_payload().size() << "]";
|
||||
} else {
|
||||
foo << msg->get_payload();
|
||||
}
|
||||
}
|
||||
|
||||
foo << "\"}";
|
||||
|
||||
for (it = m_admin_connections.begin(); it != m_admin_connections.end(); it++) {
|
||||
(*it)->send(foo.str(),false);
|
||||
}
|
||||
}
|
||||
|
||||
connection->recycle(msg);
|
||||
}
|
||||
|
||||
void command_error(connection_ptr connection,const std::string msg) {
|
||||
connection->send("{\"type\":\"error\",\"value\":\""+msg+"\"}");
|
||||
}
|
||||
|
||||
// in order to keep parsing this command language as simple as possible
|
||||
// the following values must be escaped (with \) if they are to appear
|
||||
// literally in string arguments: :,;=\
|
||||
|
||||
// close: [reason; code=1000; msg=X], [all]
|
||||
// (instructs the opposite end to close with given optional code/msg)
|
||||
void handle_close(connection_ptr connection,
|
||||
const std::map<std::string,std::string> args)
|
||||
{
|
||||
if (args.size() == 0) {
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
|
||||
(*it)->close(websocketpp::close::status::NORMAL);
|
||||
}
|
||||
} else {
|
||||
command_error(connection,"close arguments not supported");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_send(connection_ptr connection,
|
||||
const std::map<std::string,std::string> args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void http(connection_ptr connection) {
|
||||
std::stringstream foo;
|
||||
|
||||
foo << "<html><body><p>" << m_connections.size() << " current connections.</p></body></html>";
|
||||
|
||||
connection->set_body(foo.str());
|
||||
}
|
||||
|
||||
long get_ms(boost::posix_time::ptime s) {
|
||||
boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
|
||||
boost::posix_time::time_period period(s,now);
|
||||
return period.length().total_milliseconds();
|
||||
}
|
||||
|
||||
void on_timer(const boost::system::error_code& error) {
|
||||
// there is new data. This is the first time that there is no new data
|
||||
|
||||
//if (m_messages != m_messages_cache || m_data != m_data_cache) {
|
||||
|
||||
//boost::posix_time::time_period period(m_last_time,now);
|
||||
//m_last_time = now;
|
||||
|
||||
|
||||
|
||||
/*{
|
||||
type: stats
|
||||
connections: int
|
||||
admin_connections: int
|
||||
messages: [
|
||||
{
|
||||
id: int
|
||||
hash: string
|
||||
sent: int
|
||||
acked: int
|
||||
|
||||
}
|
||||
]
|
||||
}*/
|
||||
|
||||
|
||||
long milli_seconds = get_ms(m_epoch);
|
||||
|
||||
//double seconds = milli_seconds/1000.0;
|
||||
|
||||
//m_messages_cache = m_messages;
|
||||
//m_data_cache = m_data;
|
||||
|
||||
//m_messages_sent += m_messages;
|
||||
//m_data_sent += m_data;
|
||||
|
||||
//std::cout << "m: " << m_messages
|
||||
// << " milli: " << milli_seconds
|
||||
// << std::endl;
|
||||
|
||||
/*
|
||||
<< ",\"messages\":" << m_messages
|
||||
<< ",\"bytes\":" << m_data
|
||||
<< ",\"messages_sent\":" << m_messages_sent
|
||||
<< ",\"messages_acked\":" << m_messages_acked
|
||||
<< ",\"bytes_sent\":" << m_data_sent
|
||||
*/
|
||||
|
||||
std::stringstream foo;
|
||||
foo << "{\"type\":\"stats\""
|
||||
<< ",\"timestamp\":" << milli_seconds
|
||||
<< ",\"connections\":" << m_connections.size()
|
||||
<< ",\"admin_connections\":" << m_admin_connections.size()
|
||||
<< ",\"messages\":[";
|
||||
|
||||
std::map<std::string,struct msg>::iterator msg_it;
|
||||
std::map<std::string,struct msg>::iterator last = m_msgs.end();
|
||||
if (m_msgs.size() > 0) {
|
||||
last--;
|
||||
}
|
||||
|
||||
for (msg_it = m_msgs.begin(); msg_it != m_msgs.end(); msg_it++) {
|
||||
foo << "{\"id\":" << (*msg_it).second.id
|
||||
<< ",\"hash\":\"" << (*msg_it).second.hash << "\""
|
||||
<< ",\"sent\":" << (*msg_it).second.sent
|
||||
<< ",\"acked\":" << (*msg_it).second.acked
|
||||
<< ",\"size\":" << (*msg_it).second.size
|
||||
<< ",\"time\":" << (*msg_it).second.time
|
||||
<< "}" << (msg_it == last ? "" : ",");
|
||||
}
|
||||
|
||||
foo << "]}";
|
||||
|
||||
//m_msgs.clear();
|
||||
|
||||
//<< ((m_messages_cache * seconds)*1000) << ",\"data\":"
|
||||
//<< ((m_data_cache * seconds)*1000) << ",\"messages_sent\":"
|
||||
//<< m_messages_sent <<",\"data_sent\":" << m_data_sent << "}";
|
||||
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
for (it = m_admin_connections.begin(); it != m_admin_connections.end(); it++) {
|
||||
(*it)->send(foo.str(),false);
|
||||
}
|
||||
|
||||
//m_messages = 0;
|
||||
//m_data = 0;
|
||||
//}
|
||||
|
||||
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
||||
m_timer->async_wait(boost::bind(&type::on_timer,this,boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void on_fail(connection_ptr connection) {
|
||||
std::cout << "connection failed" << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int m_messages;
|
||||
size_t m_data;
|
||||
unsigned int m_messages_cache;
|
||||
size_t m_data_cache;
|
||||
unsigned int m_messages_sent;
|
||||
size_t m_data_sent;
|
||||
boost::shared_ptr<boost::asio::deadline_timer> m_timer;
|
||||
boost::posix_time::ptime m_epoch;
|
||||
boost::posix_time::ptime m_last_time;
|
||||
|
||||
size_t m_messages_acked;
|
||||
std::map<std::string,size_t> m_ack_stats;
|
||||
|
||||
int m_nextid;
|
||||
std::map<std::string,struct msg> m_msgs;
|
||||
|
||||
std::set<connection_ptr> m_connections;
|
||||
std::set<connection_ptr> m_admin_connections;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
unsigned short port = 9002;
|
||||
bool tls = false;
|
||||
@@ -532,7 +85,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
try {
|
||||
if (tls) {
|
||||
tls_handler_ptr h(new broadcast_server_handler<tls_endpoint_type>());
|
||||
tls_handler_ptr h(new websocketpp::broadcast::server_handler<tls_endpoint_type>());
|
||||
tls_endpoint_type e(h);
|
||||
|
||||
e.alog().unset_level(websocketpp::log::alevel::ALL);
|
||||
@@ -541,7 +94,7 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Starting Secure WebSocket broadcast server on port " << port << std::endl;
|
||||
e.listen(port);
|
||||
} else {
|
||||
plain_handler_ptr h(new broadcast_server_handler<plain_endpoint_type>());
|
||||
plain_handler_ptr h(new websocketpp::broadcast::server_handler<plain_endpoint_type>());
|
||||
plain_endpoint_type e(h);
|
||||
|
||||
e.alog().set_level(websocketpp::log::alevel::ALL);
|
||||
|
||||
99
examples/broadcast_server_tls/wscmd.hpp
Normal file
99
examples/broadcast_server_tls/wscmd.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. 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 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
|
||||
* 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;
|
||||
* 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 WSCMD_HPP
|
||||
#define WSCMD_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace wscmd {
|
||||
// Parses a wscmd string.
|
||||
|
||||
// command structure
|
||||
// command:arg1=val1;arg2=val2;arg3=val3;
|
||||
|
||||
// commands
|
||||
// ack: messages to ack
|
||||
// example: `ack:e3458d0aceff8b70a3e5c0afec632881=38;e3458d0aceff8b70a3e5c0afec632881=42;`
|
||||
|
||||
// send: [vals]
|
||||
// message; opcode=X; payload="X"
|
||||
// frame; [fuzzer stuff]
|
||||
|
||||
// close:code=1000;reason=msg;
|
||||
// (instructs the opposite end to close with given optional code/msg)
|
||||
typedef std::map<std::string,std::string> arg_list;
|
||||
|
||||
struct cmd {
|
||||
// TODO: move semantics
|
||||
std::string command;
|
||||
arg_list args;
|
||||
};
|
||||
|
||||
wscmd::cmd parse(const std::string& m);
|
||||
|
||||
wscmd::cmd parse(const std::string& m) {
|
||||
cmd command;
|
||||
std::string::size_type start;
|
||||
std::string::size_type end;
|
||||
|
||||
start = m.find(":",0);
|
||||
|
||||
if (start != std::string::npos) {
|
||||
command.command = m.substr(0,start);
|
||||
|
||||
start++; // skip the colon
|
||||
end = m.find(";",start);
|
||||
|
||||
// find all semicolons
|
||||
while (end != std::string::npos) {
|
||||
std::string arg;
|
||||
std::string val;
|
||||
|
||||
std::string::size_type sep = m.find("=",start);
|
||||
|
||||
if (sep != std::string::npos) {
|
||||
arg = m.substr(start,sep-start);
|
||||
val = m.substr(sep+1,end-sep-1);
|
||||
} else {
|
||||
arg = m.substr(start,end-start);
|
||||
val = "";
|
||||
}
|
||||
|
||||
command.args[arg] = val;
|
||||
|
||||
start = end+1;
|
||||
end = m.find(";",start);
|
||||
}
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
} // namespace wscmd
|
||||
|
||||
#endif // WSCMD_HPP
|
||||
@@ -102,6 +102,50 @@ namespace websocketpp {
|
||||
}
|
||||
}
|
||||
|
||||
namespace frame {
|
||||
// Opcodes are 4 bits
|
||||
// See spec section 5.2
|
||||
namespace opcode {
|
||||
enum value {
|
||||
CONTINUATION = 0x0,
|
||||
TEXT = 0x1,
|
||||
BINARY = 0x2,
|
||||
RSV3 = 0x3,
|
||||
RSV4 = 0x4,
|
||||
RSV5 = 0x5,
|
||||
RSV6 = 0x6,
|
||||
RSV7 = 0x7,
|
||||
CLOSE = 0x8,
|
||||
PING = 0x9,
|
||||
PONG = 0xA,
|
||||
CONTROL_RSVB = 0xB,
|
||||
CONTROL_RSVC = 0xC,
|
||||
CONTROL_RSVD = 0xD,
|
||||
CONTROL_RSVE = 0xE,
|
||||
CONTROL_RSVF = 0xF,
|
||||
};
|
||||
|
||||
inline bool reserved(value v) {
|
||||
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 = 0x7FFFFFFFFFFFFFFF;//2^63
|
||||
}
|
||||
} // namespace frame
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBSOCKET_CONSTANTS_HPP
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <iostream> // temporary?
|
||||
#include <vector>
|
||||
@@ -258,10 +257,12 @@ public:
|
||||
// stuff about switching handlers on the fly
|
||||
// TODO: organize more
|
||||
void set_handler(handler_ptr new_handler) {
|
||||
m_endpoint.elog().at(log::elevel::FATAL)
|
||||
<< "Tried to switch to a NULL handler." << log::endl;
|
||||
|
||||
if (!new_handler) {
|
||||
throw "TODO";
|
||||
m_endpoint.elog().at(log::elevel::FATAL)
|
||||
<< "Tried to switch to a NULL handler." << log::endl;
|
||||
terminate(true);
|
||||
return;
|
||||
}
|
||||
|
||||
handler_ptr old_handler = get_handler();
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#include "md5.h"
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
// could be compiled separately
|
||||
|
||||
116
src/messages/data.cpp
Normal file
116
src/messages/data.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. 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 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
|
||||
* 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;
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
#include "../processors/processor.hpp"
|
||||
|
||||
using websocketpp::message::data;
|
||||
|
||||
data::data() {
|
||||
m_payload.reserve(PAYLOAD_SIZE_INIT);
|
||||
}
|
||||
|
||||
websocketpp::frame::opcode::value data::get_opcode() const {
|
||||
return m_opcode;
|
||||
}
|
||||
|
||||
const std::string& data::get_payload() const {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
uint64_t data::process_payload(std::istream& input,uint64_t size) {
|
||||
unsigned char c;
|
||||
const uint64_t new_size = m_payload.size() + size;
|
||||
uint64_t i;
|
||||
|
||||
if (new_size > PAYLOAD_SIZE_MAX) {
|
||||
// TODO: real exception
|
||||
throw processor::exception("Message too big",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
if (new_size > m_payload.capacity()) {
|
||||
m_payload.reserve(std::max(new_size,static_cast<uint64_t>(2*m_payload.capacity())));
|
||||
}
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (input.good()) {
|
||||
c = input.get();
|
||||
} else if (input.eof()) {
|
||||
break;
|
||||
} else {
|
||||
// istream read error? throw?
|
||||
throw processor::exception("istream read error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
if (input.good()) {
|
||||
process_character(c);
|
||||
} else if (input.eof()) {
|
||||
break;
|
||||
} else {
|
||||
// istream read error? throw?
|
||||
throw processor::exception("istream read error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// successfully read all bytes
|
||||
return i;
|
||||
}
|
||||
|
||||
void data::process_character(unsigned char c) {
|
||||
if (m_masking_index >= 0) {
|
||||
c = c ^ m_masking_key[(m_masking_index++)%4];
|
||||
}
|
||||
|
||||
if (m_opcode == frame::opcode::TEXT && !m_validator.consume(static_cast<uint32_t>((unsigned char)(c)))) {
|
||||
throw processor::exception("Invalid UTF8 data",processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
|
||||
// add c to payload
|
||||
m_payload.push_back(c);
|
||||
}
|
||||
|
||||
void data::reset(frame::opcode::value opcode) {
|
||||
m_opcode = opcode;
|
||||
m_masking_index = 0;
|
||||
m_payload.resize(0);
|
||||
m_validator.reset();
|
||||
}
|
||||
|
||||
void data::complete() {
|
||||
if (m_opcode == frame::opcode::TEXT) {
|
||||
if (!m_validator.complete()) {
|
||||
throw processor::exception("Invalid UTF8 data",processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void data::set_masking_key(int32_t key) {
|
||||
*reinterpret_cast<int32_t*>(m_masking_key) = key;
|
||||
m_masking_index = (key == 0 ? -1 : 0);
|
||||
}
|
||||
@@ -28,100 +28,27 @@
|
||||
#ifndef WEBSOCKET_DATA_MESSAGE_HPP
|
||||
#define WEBSOCKET_DATA_MESSAGE_HPP
|
||||
|
||||
#include "../processors/processor.hpp"
|
||||
#include "../websocket_frame.hpp"
|
||||
#include "../common.hpp"
|
||||
#include "../utf8_validator/utf8_validator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace message {
|
||||
|
||||
class data {
|
||||
public:
|
||||
data() {
|
||||
m_payload.reserve(PAYLOAD_SIZE_INIT);
|
||||
}
|
||||
data();
|
||||
|
||||
frame::opcode::value get_opcode() const;
|
||||
const std::string& get_payload() const;
|
||||
|
||||
frame::opcode::value get_opcode() const {
|
||||
return m_opcode;
|
||||
};
|
||||
|
||||
const std::string& get_payload() const {
|
||||
return m_payload;
|
||||
};
|
||||
|
||||
uint64_t process_payload(std::istream& input,uint64_t size) {
|
||||
unsigned char c;
|
||||
const uint64_t new_size = m_payload.size() + size;
|
||||
uint64_t i;
|
||||
|
||||
if (new_size > PAYLOAD_SIZE_MAX) {
|
||||
// TODO: real exception
|
||||
throw processor::exception("Message too big",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
if (new_size > m_payload.capacity()) {
|
||||
m_payload.reserve(std::max(new_size,static_cast<uint64_t>(2*m_payload.capacity())));
|
||||
}
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (input.good()) {
|
||||
c = input.get();
|
||||
} else if (input.eof()) {
|
||||
break;
|
||||
} else {
|
||||
// istream read error? throw?
|
||||
throw processor::exception("istream read error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
if (input.good()) {
|
||||
process_character(c);
|
||||
} else if (input.eof()) {
|
||||
break;
|
||||
} else {
|
||||
// istream read error? throw?
|
||||
throw processor::exception("istream read error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// successfully read all bytes
|
||||
return i;
|
||||
}
|
||||
|
||||
void process_character(unsigned char c) {
|
||||
if (m_masking_index >= 0) {
|
||||
c = c ^ m_masking_key[(m_masking_index++)%4];
|
||||
}
|
||||
|
||||
if (m_opcode == frame::opcode::TEXT && !m_validator.consume(static_cast<uint32_t>((unsigned char)(c)))) {
|
||||
throw processor::exception("Invalid UTF8 data",processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
|
||||
// add c to payload
|
||||
m_payload.push_back(c);
|
||||
}
|
||||
|
||||
void reset(frame::opcode::value opcode) {
|
||||
m_opcode = opcode;
|
||||
m_masking_index = 0;
|
||||
m_payload.resize(0);
|
||||
m_validator.reset();
|
||||
}
|
||||
|
||||
void complete() {
|
||||
if (m_opcode == frame::opcode::TEXT) {
|
||||
if (!m_validator.complete()) {
|
||||
throw processor::exception("Invalid UTF8 data",processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_masking_key(int32_t key) {
|
||||
*reinterpret_cast<int32_t*>(m_masking_key) = key;
|
||||
m_masking_index = (key == 0 ? -1 : 0);
|
||||
}
|
||||
uint64_t process_payload(std::istream& input,uint64_t size);
|
||||
void process_character(unsigned char c);
|
||||
void reset(frame::opcode::value opcode);
|
||||
void complete();
|
||||
void set_masking_key(int32_t key);
|
||||
private:
|
||||
static const uint64_t PAYLOAD_SIZE_INIT = 1000; // 1KB
|
||||
static const uint64_t PAYLOAD_SIZE_MAX = 100000000;// 100MB
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "processor.hpp"
|
||||
|
||||
#include "../md5/md5.h"
|
||||
#include "../md5/md5.hpp"
|
||||
#include "../network_utilities.hpp"
|
||||
|
||||
@@ -74,7 +73,8 @@ public:
|
||||
memcpy(&key_final[8],request.header("Sec-WebSocket-Key3").c_str(),8);
|
||||
|
||||
// md5
|
||||
m_key3 = md5_hash_string(key_final);
|
||||
m_key3 = key_final;
|
||||
m_key3 = md5_hash_string(m_key3);
|
||||
|
||||
response.add_header("Upgrade","websocket");
|
||||
response.add_header("Connection","Upgrade");
|
||||
|
||||
@@ -158,9 +158,9 @@ public:
|
||||
// handler interface callback base class
|
||||
class handler_interface {
|
||||
public:
|
||||
virtual void validate(connection_ptr connection) {};
|
||||
virtual void on_open(connection_ptr connection) {};
|
||||
virtual void on_close(connection_ptr connection) {};
|
||||
virtual void validate(connection_ptr connection) {}
|
||||
virtual void on_open(connection_ptr connection) {}
|
||||
virtual void on_close(connection_ptr connection) {}
|
||||
virtual void on_fail(connection_ptr connection) {}
|
||||
|
||||
virtual void on_message(connection_ptr connection,message::data_ptr) {};
|
||||
|
||||
@@ -94,7 +94,12 @@ public:
|
||||
|
||||
void init() {
|
||||
m_context_ptr = m_connection.get_handler()->on_tls_init();
|
||||
m_socket_ptr = ssl_socket_ptr(new ssl_socket(m_endpoint.get_io_service(),*m_context_ptr));
|
||||
|
||||
if (!m_context_ptr) {
|
||||
throw "handler was unable to init tls, connection error";
|
||||
}
|
||||
|
||||
m_socket_ptr = ssl_socket_ptr(new ssl_socket(m_endpoint.get_io_service(),*m_context_ptr));
|
||||
}
|
||||
|
||||
void async_init(boost::function<void(const boost::system::error_code&)> callback)
|
||||
|
||||
@@ -28,11 +28,9 @@
|
||||
#ifndef WEBSOCKETPP_URI_HPP
|
||||
#define WEBSOCKETPP_URI_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "common.hpp"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <exception>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
|
||||
@@ -28,53 +28,10 @@
|
||||
#ifndef WEBSOCKET_FRAME_HPP
|
||||
#define WEBSOCKET_FRAME_HPP
|
||||
|
||||
namespace websocketpp {
|
||||
namespace frame {
|
||||
// Opcodes are 4 bits
|
||||
// See spec section 5.2
|
||||
namespace opcode {
|
||||
enum value {
|
||||
CONTINUATION = 0x0,
|
||||
TEXT = 0x1,
|
||||
BINARY = 0x2,
|
||||
RSV3 = 0x3,
|
||||
RSV4 = 0x4,
|
||||
RSV5 = 0x5,
|
||||
RSV6 = 0x6,
|
||||
RSV7 = 0x7,
|
||||
CLOSE = 0x8,
|
||||
PING = 0x9,
|
||||
PONG = 0xA,
|
||||
CONTROL_RSVB = 0xB,
|
||||
CONTROL_RSVC = 0xC,
|
||||
CONTROL_RSVD = 0xD,
|
||||
CONTROL_RSVE = 0xE,
|
||||
CONTROL_RSVF = 0xF,
|
||||
};
|
||||
|
||||
inline bool reserved(value v) {
|
||||
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 = 0x7FFFFFFFFFFFFFFF;//2^63
|
||||
}
|
||||
} // namespace frame
|
||||
} // namespace websocketpp
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
|
||||
|
||||
#include "network_utilities.hpp"
|
||||
#include "processors/processor.hpp"
|
||||
#include "utf8_validator/utf8_validator.hpp"
|
||||
@@ -85,7 +42,6 @@ namespace frame {
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
B67324B01491A81600FC2B04 /* libboost_regex.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B6DF1CBF1434AF6A0029A1B1 /* libboost_regex.dylib */; };
|
||||
B67324B11491A81600FC2B04 /* libboost_system.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B6DF1CBC1434AE070029A1B1 /* libboost_system.dylib */; };
|
||||
B67324B21491A84000FC2B04 /* libboost_thread.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B682888E14374689002BA48B /* libboost_thread.dylib */; };
|
||||
B6826CBC14A0D75A006DD3F3 /* data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6826CBB14A0D75A006DD3F3 /* data.cpp */; };
|
||||
B6826CBD14A0D75A006DD3F3 /* data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6826CBB14A0D75A006DD3F3 /* data.cpp */; };
|
||||
B68288871437460E002BA48B /* chat_client_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6828875143745DA002BA48B /* chat_client_handler.cpp */; };
|
||||
B68288881437460E002BA48B /* chat_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6828877143745DA002BA48B /* chat_client.cpp */; };
|
||||
B682888914374617002BA48B /* libwebsocketpp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B6DF1C721434A8280029A1B1 /* libwebsocketpp.dylib */; };
|
||||
@@ -268,6 +270,11 @@
|
||||
B673249C1491A50000FC2B04 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||
B673249D1491A51E00FC2B04 /* stress_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stress_client.cpp; sourceTree = "<group>"; };
|
||||
B67324A21491A7F100FC2B04 /* stress_client */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stress_client; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B6826CB6149F7037006DD3F3 /* broadcast_server_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = broadcast_server_handler.hpp; sourceTree = "<group>"; };
|
||||
B6826CB814A0C483006DD3F3 /* broadcast_admin_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = broadcast_admin_handler.hpp; sourceTree = "<group>"; };
|
||||
B6826CB914A0C483006DD3F3 /* broadcast_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = broadcast_handler.hpp; sourceTree = "<group>"; };
|
||||
B6826CBA14A0C49B006DD3F3 /* wscmd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wscmd.hpp; sourceTree = "<group>"; };
|
||||
B6826CBB14A0D75A006DD3F3 /* data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = data.cpp; path = src/messages/data.cpp; sourceTree = "<group>"; };
|
||||
B6828875143745DA002BA48B /* chat_client_handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client_handler.cpp; path = examples/chat_client/chat_client_handler.cpp; sourceTree = "<group>"; };
|
||||
B6828876143745DA002BA48B /* chat_client_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = chat_client_handler.hpp; path = examples/chat_client/chat_client_handler.hpp; sourceTree = "<group>"; };
|
||||
B6828877143745DA002BA48B /* chat_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client.cpp; path = examples/chat_client/chat_client.cpp; sourceTree = "<group>"; };
|
||||
@@ -501,6 +508,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B663885F1487FE6C00DDAE13 /* data.hpp */,
|
||||
B6826CBB14A0D75A006DD3F3 /* data.cpp */,
|
||||
B66388601487FE6C00DDAE13 /* control.hpp */,
|
||||
);
|
||||
name = messages;
|
||||
@@ -565,7 +573,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B673248214919D6600FC2B04 /* broadcast_admin.html */,
|
||||
B6826CBA14A0C49B006DD3F3 /* wscmd.hpp */,
|
||||
B673248314919D6600FC2B04 /* broadcast_server_tls.cpp */,
|
||||
B6826CB814A0C483006DD3F3 /* broadcast_admin_handler.hpp */,
|
||||
B6826CB914A0C483006DD3F3 /* broadcast_handler.hpp */,
|
||||
B6826CB6149F7037006DD3F3 /* broadcast_server_handler.hpp */,
|
||||
B673248414919D6600FC2B04 /* Makefile */,
|
||||
);
|
||||
name = broadcast_server_tls;
|
||||
@@ -1111,6 +1123,7 @@
|
||||
B6DF1C8A1434AC330029A1B1 /* sha1.cpp in Sources */,
|
||||
B6727429148517180029CF3E /* uri.cpp in Sources */,
|
||||
B653A719148AB555004D7BD9 /* hybi_header.cpp in Sources */,
|
||||
B6826CBC14A0D75A006DD3F3 /* data.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1124,6 +1137,7 @@
|
||||
B6DF1C8B1434AC330029A1B1 /* sha1.cpp in Sources */,
|
||||
B672742A148517180029CF3E /* uri.cpp in Sources */,
|
||||
B653A71A148AB555004D7BD9 /* hybi_header.cpp in Sources */,
|
||||
B6826CBD14A0D75A006DD3F3 /* data.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1631,6 +1645,7 @@
|
||||
B6732461148FAEEC00FC2B04 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B6732478148FB0FC00FC2B04 /* Build configuration list for PBXNativeTarget "fuzzing_client" */ = {
|
||||
isa = XCConfigurationList;
|
||||
@@ -1639,6 +1654,7 @@
|
||||
B673247A148FB0FC00FC2B04 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B67324901491A16500FC2B04 /* Build configuration list for PBXNativeTarget "broadcast_server" */ = {
|
||||
isa = XCConfigurationList;
|
||||
@@ -1647,6 +1663,7 @@
|
||||
B67324921491A16500FC2B04 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B67324A91491A7F200FC2B04 /* Build configuration list for PBXNativeTarget "stress_client" */ = {
|
||||
isa = XCConfigurationList;
|
||||
@@ -1655,6 +1672,7 @@
|
||||
B67324AB1491A7F200FC2B04 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B6828884143745F2002BA48B /* Build configuration list for PBXNativeTarget "chat_client" */ = {
|
||||
isa = XCConfigurationList;
|
||||
|
||||
Reference in New Issue
Block a user