Init project

This commit is contained in:
dijunkun
2023-07-13 14:17:34 +08:00
commit ef6a04dc97
120 changed files with 26696 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
# VSCode cache
.vscode
projectx.code-workspace

1
README.md Normal file
View File

@@ -0,0 +1 @@
# projectx

BIN
doc/Architecture.vsdx Normal file

Binary file not shown.

124
src/ice/ice_agent.cpp Normal file
View File

@@ -0,0 +1,124 @@
#include "ice_agent.h"
#include <string.h>
#include <iostream>
#include "log.h"
IceAgent::IceAgent() {}
IceAgent::~IceAgent() {}
int IceAgent::CreateIceAgent(juice_cb_state_changed_t on_state_changed,
juice_cb_candidate_t on_candidate,
juice_cb_gathering_done_t on_gathering_done,
juice_cb_recv_t on_recv, void *user_ptr) {
// juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
juice_config_t config;
memset(&config, 0, sizeof(config));
// STUN server example
config.stun_server_host = "120.77.216.215";
config.stun_server_port = 3478;
config.cb_state_changed = on_state_changed;
config.cb_candidate = on_candidate;
config.cb_gathering_done = on_gathering_done;
config.cb_recv = on_recv;
config.user_ptr = user_ptr;
agent_ = juice_create(&config);
return 0;
}
int IceAgent::DestoryIceAgent() {
juice_destroy(agent_);
return 0;
}
char *IceAgent::GenerateLocalSdp() {
if (nullptr == agent_) {
LOG_INFO("agent_ is nullptr");
return nullptr;
}
juice_get_local_description(agent_, local_sdp_, JUICE_MAX_SDP_STRING_LEN);
LOG_INFO("Generate local sdp:[\n{}]", local_sdp_);
return local_sdp_;
}
int IceAgent::SetRemoteSdp(const char *remote_sdp) {
LOG_INFO("Set remote sdp");
juice_set_remote_description(agent_, remote_sdp);
LOG_INFO("Remote description:[\n{}]", remote_sdp);
return 0;
}
int IceAgent::GatherCandidates() {
LOG_INFO("Gather candidates");
juice_gather_candidates(agent_);
return 0;
}
juice_state_t IceAgent::GetIceState() {
state_ = juice_get_state(agent_);
return state_;
}
bool IceAgent::GetSelectedCandidates() {
char local[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
char remote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
bool success = state_ == JUICE_STATE_COMPLETED;
if (success &= (juice_get_selected_candidates(
agent_, local, JUICE_MAX_CANDIDATE_SDP_STRING_LEN, remote,
JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0)) {
LOG_INFO("Local candidate 1: {}", local);
LOG_INFO("Remote candidate 1: {}", remote);
if ((!strstr(local, "typ host") && !strstr(local, "typ prflx")) ||
(!strstr(remote, "typ host") && !strstr(remote, "typ prflx")))
success = false; // local connection should be possible
}
return success;
}
bool IceAgent::GetSelectedAddresses() {
char localAddr[JUICE_MAX_ADDRESS_STRING_LEN];
char remoteAddr[JUICE_MAX_ADDRESS_STRING_LEN];
bool success = state_ == JUICE_STATE_COMPLETED;
if (success &= (juice_get_selected_addresses(
agent_, localAddr, JUICE_MAX_ADDRESS_STRING_LEN,
remoteAddr, JUICE_MAX_ADDRESS_STRING_LEN) == 0)) {
LOG_INFO("Local address 1: {}", localAddr);
LOG_INFO("Remote address 1: {}", remoteAddr);
}
return success;
}
int IceAgent::AddRemoteCandidates(const char *remote_candidates) {
juice_add_remote_candidate(agent_, remote_candidates);
return 0;
}
int IceAgent::SetRemoteGatheringDone() {
juice_set_remote_gathering_done(agent_);
return 0;
}
int IceAgent::Send(const char *data, size_t size) {
juice_send(agent_, data, size);
return 0;
}

42
src/ice/ice_agent.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef _ICE_AGENT_H_
#define _ICE_AGENT_H_
#include "juice/juice.h"
class IceAgent {
public:
IceAgent();
~IceAgent();
int CreateIceAgent(juice_cb_state_changed_t on_state_changed,
juice_cb_candidate_t on_candidate,
juice_cb_gathering_done_t on_gathering_done,
juice_cb_recv_t on_recv, void* user_ptr);
int DestoryIceAgent();
char* GenerateLocalSdp();
int SetRemoteSdp(const char* remote_sdp);
int GatherCandidates();
juice_state_t GetIceState();
bool GetSelectedCandidates();
bool GetSelectedAddresses();
int AddRemoteCandidates(const char* remote_candidates);
int SetRemoteGatheringDone();
int Send(const char* data, size_t size);
private:
juice_agent_t* agent_ = nullptr;
char local_sdp_[JUICE_MAX_SDP_STRING_LEN];
juice_state_t state_;
};
#endif

267
src/ice/ice_transport.cpp Normal file
View File

@@ -0,0 +1,267 @@
#include "ice_transport.h"
#include <map>
#include <nlohmann/json.hpp>
#include "log.h"
using nlohmann::json;
static const std::map<std::string, unsigned int> siganl_types{
{"connection_id", 1},
{"offer", 2},
{"transport_id", 3},
{"remote_sdp", 4},
{"candidate", 5}};
const std::vector<std::string> ice_status = {
"JUICE_STATE_DISCONNECTED", "JUICE_STATE_GATHERING",
"JUICE_STATE_CONNECTING", "JUICE_STATE_CONNECTED",
"JUICE_STATE_COMPLETED", "JUICE_STATE_FAILED"};
IceTransport::IceTransport(
WsTransport *ice_ws_transport,
std::function<void(const char *, size_t)> on_receive_ice_msg)
: ice_ws_transport_(ice_ws_transport),
on_receive_ice_msg_cb_(on_receive_ice_msg) {}
IceTransport::~IceTransport() {}
int IceTransport::InitIceTransport() {
ice_agent_ = new IceAgent();
ice_agent_->CreateIceAgent(
[](juice_agent_t *agent, juice_state_t state, void *user_ptr) {
LOG_INFO("state_change: {}", ice_status[state]);
},
[](juice_agent_t *agent, const char *sdp, void *user_ptr) {
LOG_INFO("candadite: {}", sdp);
// trickle
// static_cast<IceTransport
// *>(user_ptr)->SendOfferLocalCandidate(sdp);
},
[](juice_agent_t *agent, void *user_ptr) {
LOG_INFO("gather_done");
// non-trickle
if (user_ptr) {
static_cast<IceTransport *>(user_ptr)->GetLocalSdp();
static_cast<IceTransport *>(user_ptr)->SendOffer();
}
},
[](juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
LOG_INFO("on_recv");
if (user_ptr &&
static_cast<IceTransport *>(user_ptr)->on_receive_ice_msg_cb_) {
static_cast<IceTransport *>(user_ptr)->on_receive_ice_msg_cb_(data,
size);
}
},
this);
return 0;
}
int IceTransport::InitIceTransport(std::string const &id) {
transport_id_ = id;
ice_agent_->CreateIceAgent(
[](juice_agent_t *agent, juice_state_t state, void *user_ptr) {
LOG_INFO("state_change: {}", ice_status[state]);
},
[](juice_agent_t *agent, const char *sdp, void *user_ptr) {
LOG_INFO("candadite: {}", sdp);
// trickle
// static_cast<PeerConnection
// *>(user_ptr)->SendAnswerLocalCandidate(sdp);
},
[](juice_agent_t *agent, void *user_ptr) {
LOG_INFO("gather_done");
// non-trickle
if (user_ptr) {
static_cast<IceTransport *>(user_ptr)->CreateAnswer();
static_cast<IceTransport *>(user_ptr)->SendAnswer();
}
},
[](juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
LOG_INFO("on_recv");
if (user_ptr &&
static_cast<IceTransport *>(user_ptr)->on_receive_ice_msg_cb_) {
static_cast<IceTransport *>(user_ptr)->on_receive_ice_msg_cb_(data,
size);
}
},
this);
return 0;
}
int IceTransport::DestroyIceTransport() {
if (ice_agent_) {
delete ice_agent_;
}
return 0;
}
int IceTransport::CreateTransport() {
LOG_INFO("Create transport");
offer_peer_ = true;
// if (SignalStatus::Connected != signal_status_) {
// LOG_ERROR("Not connect to signalserver");
// return -1;
// }
json message = {{"type", "create_transport"}};
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
LOG_INFO("Send msg: {}", message.dump().c_str());
}
CreateOffer();
return 0;
}
int IceTransport::CreateTransport(std::string transport_id) {
LOG_INFO("Join transport");
offer_peer_ = false;
// if (SignalStatus::Connected != signal_status_) {
// LOG_ERROR("Not connect to signalserver");
// return -1;
// }
QueryRemoteSdp(transport_id);
return 0;
}
int IceTransport::GatherCandidates() {
ice_agent_->GatherCandidates();
return 0;
}
int IceTransport::GetLocalSdp() {
local_sdp_ = ice_agent_->GenerateLocalSdp();
return 0;
}
int IceTransport::SetRemoteSdp(const std::string &remote_sdp) {
ice_agent_->SetRemoteSdp(remote_sdp.c_str());
return 0;
}
int IceTransport::AddRemoteCandidate(const std::string &remote_candidate) {
ice_agent_->AddRemoteCandidates(remote_candidate.c_str());
return 0;
}
int IceTransport::CreateOffer() {
LOG_INFO("Create offer");
GatherCandidates();
return 0;
}
int IceTransport::SendOffer() {
json message = {
{"type", "offer"}, {"transport_id", transport_id_}, {"sdp", local_sdp_}};
LOG_INFO("Send offer:\n{}", message.dump().c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
}
return 0;
}
int IceTransport::QueryRemoteSdp(std::string transport_id) {
json message = {{"type", "query_remote_sdp"},
{"transport_id", transport_id_}};
LOG_INFO("Query remote sdp");
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
}
return 0;
}
int IceTransport::CreateAnswer() {
GetLocalSdp();
return 0;
}
int IceTransport::SendAnswer() {
json message = {
{"type", "answer"}, {"transport_id", transport_id_}, {"sdp", local_sdp_}};
LOG_INFO("Send answer:\n{}", message.dump().c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
}
return 0;
}
int IceTransport::SendOfferLocalCandidate(const std::string &remote_candidate) {
json message = {{"type", "offer_candidate"},
{"transport_id", transport_id_},
{"sdp", remote_candidate}};
LOG_INFO("Send candidate:\n{}", message.dump().c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
}
return 0;
}
int IceTransport::SendAnswerLocalCandidate(
const std::string &remote_candidate) {
json message = {{"type", "answer_candidate"},
{"transport_id", transport_id_},
{"sdp", remote_candidate}};
LOG_INFO("Send candidate:\n{}", message.dump().c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
}
return 0;
}
int IceTransport::SendData(const char *data, size_t size) {
ice_agent_->Send(data, size);
return 0;
}
void IceTransport::OnReceiveMessage(const std::string &msg) {
auto j = json::parse(msg);
LOG_INFO("msg: {}", msg.c_str());
std::string type = j["type"];
auto itr = siganl_types.find(type);
if (itr != siganl_types.end()) {
LOG_INFO("msg type :{}", itr->first);
switch (itr->second) {
case 2: {
break;
}
case 3: {
transport_id_ = j["transport_id"].get<std::string>();
LOG_INFO("Receive local peer transport_id [{}]", transport_id_);
// SendOffer();
break;
}
case 4: {
remote_sdp_ = j["sdp"].get<std::string>();
LOG_INFO("Receive remote sdp [{}]", remote_sdp_);
SetRemoteSdp(remote_sdp_);
if (!offer_peer_) {
GatherCandidates();
}
break;
}
case 5: {
std::string candidate = j["sdp"].get<std::string>();
LOG_INFO("Receive candidate [{}]", candidate);
AddRemoteCandidate(candidate);
break;
}
default:
break;
}
}
}

66
src/ice/ice_transport.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef _ICE_TRANSPORT_H_
#define _ICE_TRANSPORT_H_
#include <iostream>
#include "ice_agent.h"
#include "ws_transport.h"
class IceTransport {
public:
IceTransport(WsTransport *ice_ws_transport,
std::function<void(const char *, size_t)> on_receive_ice_msg);
~IceTransport();
int InitIceTransport();
int InitIceTransport(std::string const &id);
int DestroyIceTransport();
int CreateTransport();
int CreateTransport(std::string transport_id);
int SendData(const char *data, size_t size);
void OnReceiveUserData(const char *data, size_t size);
void OnReceiveMessage(const std::string &msg);
private:
int GatherCandidates();
int GetLocalSdp();
int QueryRemoteSdp(std::string transport_id);
int SetRemoteSdp(const std::string &remote_sdp);
int AddRemoteCandidate(const std::string &remote_candidate);
int CreateOffer();
int SendOffer();
int CreateAnswer();
int SendAnswer();
int SendOfferLocalCandidate(const std::string &remote_candidate);
int SendAnswerLocalCandidate(const std::string &remote_candidate);
private:
IceAgent *ice_agent_ = nullptr;
WsTransport *ice_ws_transport_ = nullptr;
std::function<void(const char *, size_t)> on_receive_ice_msg_cb_ = nullptr;
std::string local_sdp_;
std::string remote_sdp_;
std::string local_candidates_;
std::string remote_candidates_;
unsigned int connection_id_ = 0;
std::string transport_id_ = "";
bool offer_peer_ = true;
};
#endif

127
src/log/log.h Normal file
View File

@@ -0,0 +1,127 @@
#ifndef _LOG_H_
#define _LOG_H_
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "spdlog/common.h"
#include "spdlog/logger.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
using namespace std::chrono;
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
// SPDLOG_TRACE(...)
// SPDLOG_DEBUG(...)
// SPDLOG_INFO(...)
// SPDLOG_WARN(...)
// SPDLOG_ERROR(...)
// SPDLOG_CRITICAL(...)
#ifdef SIGNAL_LOGGER
constexpr auto LOGGER_NAME = "siganl";
#else
constexpr auto LOGGER_NAME = "rtc";
#endif
#define LOG_INFO(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
combined_logger->flush_on(spdlog::level::info); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_INFO(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_INFO(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_WARN(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_WARN(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_WARN(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_ERROR(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_ERROR(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_ERROR(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_FATAL(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_CRITICAL(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_CRITICAL(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#endif

113
src/pc/peer_connection.cpp Normal file
View File

@@ -0,0 +1,113 @@
#include "peer_connection.h"
#include <nlohmann/json.hpp>
#include "log.h"
using nlohmann::json;
static const std::map<std::string, unsigned int> siganl_types{
{"connection_id", 1},
{"offer", 2},
{"transport_id", 3},
{"remote_sdp", 4},
{"candidate", 5}};
PeerConnection::PeerConnection() {}
PeerConnection::~PeerConnection() {}
int PeerConnection::Init(std::string const &uri) {
on_receive_ws_msg_ = [this](const std::string &msg) {
do {
} while (!ice_transport_);
auto j = json::parse(msg);
std::string type = j["type"];
auto itr = siganl_types.find(type);
if (itr != siganl_types.end()) {
LOG_INFO("msg type :{}", itr->first);
switch (itr->second) {
case 1: {
connection_id_ = j["connection_id"].get<unsigned int>();
LOG_INFO("Receive local peer connection_id [{}]", connection_id_);
signal_status_ = SignalStatus::Connected;
break;
}
default: {
ice_transport_->OnReceiveMessage(msg);
break;
}
}
}
};
on_receive_ice_msg_ = [this](const char *data, size_t size) {};
ws_transport_ = new WsTransport(on_receive_ws_msg_);
if (ws_transport_) {
ws_transport_->Connect(uri);
}
ice_transport_ = new IceTransport(ws_transport_, on_receive_ice_msg_);
ice_transport_->InitIceTransport();
do {
LOG_INFO("GetSignalStatus = {}", GetSignalStatus());
} while (SignalStatus::Connected != GetSignalStatus());
ice_transport_->CreateTransport();
return 0;
}
int PeerConnection::Init(std::string const &uri, std::string const &id) {
on_receive_ws_msg_ = [this](const std::string &msg) {
do {
} while (!ice_transport_);
auto j = json::parse(msg);
std::string type = j["type"];
auto itr = siganl_types.find(type);
if (itr != siganl_types.end()) {
LOG_INFO("msg type :{}", itr->first);
switch (itr->second) {
case 1: {
connection_id_ = j["connection_id"].get<unsigned int>();
LOG_INFO("Receive local peer connection_id [{}]", connection_id_);
signal_status_ = SignalStatus::Connected;
break;
}
default: {
ice_transport_->OnReceiveMessage(msg);
break;
}
}
}
};
on_receive_ice_msg_ = [this](const char *data, size_t size) {};
transport_id_ = id;
ws_transport_ = new WsTransport(on_receive_ws_msg_);
if (ws_transport_) {
ws_transport_->Connect(uri);
}
ice_transport_ = new IceTransport(ws_transport_, on_receive_ice_msg_);
ice_transport_->InitIceTransport(id);
do {
LOG_INFO("GetSignalStatus = {}", GetSignalStatus());
} while (SignalStatus::Connected != GetSignalStatus());
ice_transport_->CreateTransport(transport_id_);
return 0;
}
int PeerConnection::Destroy() {
if (ws_transport_) {
delete ws_transport_;
}
return 0;
}
SignalStatus PeerConnection::GetSignalStatus() { return signal_status_; }

33
src/pc/peer_connection.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef _PEER_CONNECTION_H_
#define _PEER_CONNECTION_H_
#include <iostream>
#include "ice_transport.h"
#include "ws_transport.h"
enum SignalStatus { Connecting = 0, Connected, Closed };
class PeerConnection {
public:
PeerConnection();
~PeerConnection();
public:
int Init(std::string const &uri);
int Init(std::string const &uri, std::string const &id);
int Destroy();
SignalStatus GetSignalStatus();
private:
WsTransport *ws_transport_ = nullptr;
IceTransport *ice_transport_ = nullptr;
std::function<void(const std::string &)> on_receive_ws_msg_ = nullptr;
std::function<void(const char *, size_t)> on_receive_ice_msg_ = nullptr;
unsigned int connection_id_ = 0;
std::string transport_id_ = "";
SignalStatus signal_status_ = SignalStatus::Closed;
};
#endif

101
src/rtc/rtc.cpp Normal file
View File

@@ -0,0 +1,101 @@
#include "rtc.h"
#include <iostream>
#include <nlohmann/json.hpp>
#include "ice_agent.h"
#include "log.h"
#include "peer_connection.h"
#include "ws_transport.h"
using nlohmann::json;
static const std::vector<std::string> siganl_status = {"Connecting",
"Connected", "Closed"};
class WsSender : public WsCore {
public:
WsSender() {}
~WsSender() {}
void OnReceiveMessage(const std::string &msg) {
LOG_INFO("Receive msg: {}", msg);
}
};
static WsSender *ws_client;
static PeerConnection *peer_connection;
int CreatePeerConnection(const char *uri) {
peer_connection = new PeerConnection();
peer_connection->Init(uri);
// do {
// } while (SignalStatus::Connected != peer_connection->GetSignalStatus());
// LOG_INFO("Signal status: {}",
// siganl_status[peer_connection->GetSignalStatus()]);
// peer_connection->CreateTransport();
// peer_connection->CreateOffer();
return 0;
}
int CreatePeerConnectionWithID(const char *uri, const char *id) {
peer_connection = new PeerConnection();
peer_connection->Init(uri, id);
// do {
// } while (SignalStatus::Connected != peer_connection->GetSignalStatus());
// LOG_INFO("Signal status: {}",
// siganl_status[peer_connection->GetSignalStatus()]);
// peer_connection->CreateTransport(id);
return 0;
}
int rtc() {
ws_client = new WsSender();
return 0;
}
int CreateWsClient(const char *uri) {
ws_client->Connect(uri);
return 0;
}
int WsSendMsg(const char *message) {
ws_client->Send(message);
return 0;
}
// ws_status GetWsStatus()
// {
// std::string ws_status = ws_client->GetStatus();
// if ("Connecting" == ws_status)
// {
// return ws_status::WS_CONNECTING;
// }
// else if ("Open" == ws_status)
// {
// return ws_status::WS_OPEN;
// }
// else if ("Failed" == ws_status)
// {
// return ws_status::WS_FAILED;
// }
// else if ("Closed" == ws_status)
// {
// return ws_status::WS_CLOSED;
// }
// else
// {
// return ws_status::WS_UNKNOWN;
// }
// }

30
src/rtc/rtc.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef _RTC_H_
#define _RTC_H_
enum ws_status { WS_CONNECTING = 0, WS_OPEN, WS_FAILED, WS_CLOSED, WS_UNKNOWN };
#ifdef __cplusplus
extern "C" {
#endif
int CreatePeerConnection(const char* uri);
int CreatePeerConnectionWithID(const char* uri, const char* id);
int rtc();
int ConnectToServer(const char* uri);
int RegisterPeer();
int CreateWsClient(const char* uri);
int WsSendMsg(const char* message);
ws_status GetWsStatus();
#ifdef __cplusplus
}
#endif
#endif

136
src/ws/ws_core.cpp Normal file
View File

@@ -0,0 +1,136 @@
#include "ws_core.h"
#include <cstdlib>
#include <iostream>
#include <sstream>
#include "log.h"
WsCore::WsCore() {
m_endpoint_.clear_access_channels(websocketpp::log::alevel::all);
m_endpoint_.clear_error_channels(websocketpp::log::elevel::all);
m_endpoint_.init_asio();
m_endpoint_.start_perpetual();
m_thread_ = websocketpp::lib::make_shared<websocketpp::lib::thread>(
&client::run, &m_endpoint_);
}
WsCore::~WsCore() {
m_endpoint_.stop_perpetual();
if (GetStatus() != "Open") {
// Only close open connections
return;
}
websocketpp::lib::error_code ec;
m_endpoint_.close(connection_handle_, websocketpp::close::status::going_away,
"", ec);
if (ec) {
LOG_INFO("> Error closing connection {}", ec.message());
}
m_thread_->join();
}
int WsCore::Connect(std::string const &uri) {
websocketpp::lib::error_code ec;
client::connection_ptr con = m_endpoint_.get_connection(uri, ec);
connection_handle_ = con->get_handle();
if (ec) {
LOG_INFO("> Connect initialization error: {}", ec.message());
return -1;
}
con->set_open_handler(websocketpp::lib::bind(
&WsCore::OnOpen, this, &m_endpoint_, websocketpp::lib::placeholders::_1));
con->set_fail_handler(websocketpp::lib::bind(
&WsCore::OnFail, this, &m_endpoint_, websocketpp::lib::placeholders::_1));
con->set_close_handler(
websocketpp::lib::bind(&WsCore::OnClose, this, &m_endpoint_,
websocketpp::lib::placeholders::_1));
// con->set_ping_handler(websocketpp::lib::bind(
// &WsCore::on_ping,
// this,
// websocketpp::lib::placeholders::_1,
// websocketpp::lib::placeholders::_2
// ));
con->set_pong_handler(websocketpp::lib::bind(
&WsCore::OnPong, this, websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2));
con->set_pong_timeout(1000);
con->set_pong_timeout_handler(websocketpp::lib::bind(
&WsCore::OnPongTimeout, this, websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2));
con->set_message_handler(websocketpp::lib::bind(
&WsCore::OnMessage, this, websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2));
m_endpoint_.connect(con);
return 0;
}
void WsCore::Close(websocketpp::close::status::value code, std::string reason) {
websocketpp::lib::error_code ec;
m_endpoint_.close(connection_handle_, code, reason, ec);
if (ec) {
LOG_INFO("> Error initiating close: {}", ec.message());
}
}
void WsCore::Send(std::string message) {
websocketpp::lib::error_code ec;
m_endpoint_.send(connection_handle_, message,
websocketpp::frame::opcode::text, ec);
if (ec) {
LOG_INFO("> Error sending message: {}", ec.message());
return;
}
}
void WsCore::Ping() {
websocketpp::lib::error_code ec;
std::string message = "ping";
m_endpoint_.ping(connection_handle_, message, ec);
if (ec) {
LOG_INFO("> Error sending ping");
return;
}
}
const std::string &WsCore::GetStatus() { return connection_status_; }
void WsCore::OnOpen(client *c, websocketpp::connection_hdl hdl) {
connection_status_ = "Open";
}
void WsCore::OnFail(client *c, websocketpp::connection_hdl hdl) {
connection_status_ = "Failed";
}
void WsCore::OnClose(client *c, websocketpp::connection_hdl hdl) {
connection_status_ = "Closed";
}
void WsCore::OnPong(websocketpp::connection_hdl, std::string msg) {}
void WsCore::OnPongTimeout(websocketpp::connection_hdl, std::string msg) {}
void WsCore::OnMessage(websocketpp::connection_hdl, client::message_ptr &msg) {
OnReceiveMessage(msg->get_payload());
}

54
src/ws/ws_core.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef _WS_CORE_H_
#define _WS_CORE_H_
#include <map>
#include <sstream>
#include <string>
#include "websocketpp/client.hpp"
#include "websocketpp/common/memory.hpp"
#include "websocketpp/common/thread.hpp"
#include "websocketpp/config/asio_no_tls_client.hpp"
typedef websocketpp::client<websocketpp::config::asio_client> client;
class WsCore {
public:
WsCore();
virtual ~WsCore();
int Connect(std::string const &uri);
void Close(websocketpp::close::status::value code, std::string reason);
void Send(std::string message);
void Ping();
const std::string &GetStatus();
// Callback
void OnOpen(client *c, websocketpp::connection_hdl hdl);
void OnFail(client *c, websocketpp::connection_hdl hdl);
void OnClose(client *c, websocketpp::connection_hdl hdl);
void OnPong(websocketpp::connection_hdl, std::string msg);
void OnPongTimeout(websocketpp::connection_hdl, std::string msg);
void OnMessage(websocketpp::connection_hdl, client::message_ptr &msg);
virtual void OnReceiveMessage(const std::string &msg) = 0;
private:
client m_endpoint_;
websocketpp::connection_hdl connection_handle_;
websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread_;
std::string connection_status_ = "Connecting";
};
#endif

16
src/ws/ws_transport.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "ws_transport.h"
#include "log.h"
WsTransport::WsTransport(
std::function<void(const std::string &)> on_receive_msg_cb)
: on_receive_msg_(on_receive_msg_cb) {}
WsTransport::~WsTransport() {}
void WsTransport::OnReceiveMessage(const std::string &msg) {
LOG_INFO("Receive msg: {}", msg);
if (on_receive_msg_) {
on_receive_msg_(msg);
}
}

18
src/ws/ws_transport.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef _WS_TRANSPORT_H_
#define _WS_TRANSPORT_H_
#include "ws_core.h"
class WsTransport : public WsCore {
public:
WsTransport(std::function<void(const std::string &)> on_receive_msg_cb);
~WsTransport();
public:
void OnReceiveMessage(const std::string &msg);
private:
std::function<void(const std::string &)> on_receive_msg_ = nullptr;
};
#endif

View File

@@ -0,0 +1,10 @@
#include <iostream>
#include "rtc.h"
int main(int argc, char **argv) {
CreatePeerConnectionWithID("ws://localhost:9002", "000000");
getchar();
return 0;
}

View File

@@ -0,0 +1,10 @@
#include <iostream>
#include "rtc.h"
int main(int argc, char **argv) {
CreatePeerConnection("ws://localhost:9002");
getchar();
return 0;
}

View File

@@ -0,0 +1,51 @@
#include "ws_client.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
class WsReceiver:public WsCore
{
public:
WsReceiver(){}
~WsReceiver(){}
void OnReceiveMessage(const std::string &msg)
{
LOG_INFO("Receive msg: {}", msg);
}
};
int main()
{
bool done = false;
std::string input;
WsReceiver ws_client;
LOG_INFO("connect ws://localhost:9002");
ws_client.Connect("ws://localhost:9002");
std::string status1 = ws_client.GetStatus();
while("Open" != status1)
{
status1 = ws_client.GetStatus();
}
LOG_INFO("Connect successfully!");
LOG_INFO("Send message [Hello]");
ws_client.Send("Hello");
LOG_INFO("Send ping");
ws_client.Ping();
LOG_INFO("Close conneciton");
int close_code = websocketpp::close::status::normal;
std::string reason = "User Close";
ws_client.Close(close_code, reason);
getchar();
return 0;
}

View File

@@ -0,0 +1,8 @@
#include "signal_server.h"
int main() {
SignalServer s;
// connect ws://localhost:9002
s.run();
return 0;
}

View File

@@ -0,0 +1,166 @@
#include "signal_server.h"
#include "log.h"
static const std::map<std::string, unsigned int> siganl_types{
{"create_transport", 1}, {"offer", 2}, {"query_remote_sdp", 3},
{"answer", 4}, {"offer_candidate", 5}, {"answer_candidate", 6}};
std::string gen_random_6() {
static const char alphanum[] = "0123456789";
std::string tmp_s;
tmp_s.reserve(6);
for (int i = 0; i < 6; ++i) {
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
// return tmp_s;
return "000000";
}
SignalServer::SignalServer() {
// Set logging settings
server_.set_error_channels(websocketpp::log::elevel::all);
server_.set_access_channels(websocketpp::log::alevel::none);
// Initialize Asio
server_.init_asio();
server_.set_open_handler(
std::bind(&SignalServer::on_open, this, std::placeholders::_1));
server_.set_close_handler(
std::bind(&SignalServer::on_close, this, std::placeholders::_1));
server_.set_message_handler(std::bind(&SignalServer::on_message, this,
std::placeholders::_1,
std::placeholders::_2));
server_.set_ping_handler(bind(&SignalServer::on_ping, this,
std::placeholders::_1, std::placeholders::_2));
server_.set_pong_handler(bind(&SignalServer::on_pong, this,
std::placeholders::_1, std::placeholders::_2));
}
SignalServer::~SignalServer() {}
bool SignalServer::on_open(websocketpp::connection_hdl hdl) {
connections_[hdl] = connection_id_;
LOG_INFO("New connection [{}] established", connection_id_++);
json message = {{"type", "connection_id"}, {"connection_id", connection_id_}};
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
return true;
}
bool SignalServer::on_close(websocketpp::connection_hdl hdl) {
LOG_INFO("Connection [{}] closed", connection_id_++);
connections_.erase(hdl);
return true;
}
bool SignalServer::on_ping(websocketpp::connection_hdl hdl, std::string s) {
/* Do something */
LOG_INFO("Receive ping");
return true;
}
bool SignalServer::on_pong(websocketpp::connection_hdl hdl, std::string s) {
/* Do something */
LOG_INFO("pong");
return true;
}
void SignalServer::run() {
// Listen on port 9002
server_.listen(9002);
// Queues a connection accept operation
server_.start_accept();
// Start the Asio io_service run loop
server_.run();
}
void SignalServer::send_msg(websocketpp::connection_hdl hdl, json message) {
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
}
void SignalServer::on_message(websocketpp::connection_hdl hdl,
server::message_ptr msg) {
std::string payload = msg->get_payload();
auto j = json::parse(payload);
std::string type = j["type"];
auto itr = siganl_types.find(type);
if (itr != siganl_types.end()) {
LOG_INFO("msg type: {}", itr->first);
switch (itr->second) {
case 1: {
transport_id_ = gen_random_6();
LOG_INFO("Generate transport_id [{}]", transport_id_);
json message = {{"type", "transport_id"},
{"transport_id", transport_id_}};
send_msg(hdl, message);
break;
}
case 2: {
std::string transport_id = j["transport_id"];
std::string sdp = j["sdp"];
LOG_INFO("Save transport_id[{}] with offer sdp[{}]", transport_id, sdp);
offer_sdp_map_[transport_id] = sdp;
offer_hdl_map_[transport_id] = hdl;
break;
}
case 3: {
std::string transport_id = j["transport_id"];
std::string sdp = offer_sdp_map_[transport_id_];
LOG_INFO("send offer sdp [{}]", sdp.c_str());
json message = {{"type", "remote_sdp"}, {"sdp", sdp}};
send_msg(hdl, message);
break;
}
case 4: {
std::string transport_id = j["transport_id"];
std::string sdp = j["sdp"];
LOG_INFO("Save transport_id[{}] with answer sdp[{}]", transport_id,
sdp);
answer_sdp_map_[transport_id] = sdp;
answer_hdl_map_[transport_id] = hdl;
LOG_INFO("send answer sdp [{}]", sdp.c_str());
json message = {{"type", "remote_sdp"}, {"sdp", sdp}};
send_msg(offer_hdl_map_[transport_id], message);
break;
}
case 5: {
std::string transport_id = j["transport_id"];
std::string candidate = j["sdp"];
LOG_INFO("send candidate [{}]", candidate.c_str());
json message = {{"type", "candidate"}, {"sdp", candidate}};
send_msg(answer_hdl_map_[transport_id], message);
break;
}
case 6: {
std::string transport_id = j["transport_id"];
std::string candidate = j["sdp"];
LOG_INFO("send candidate [{}]", candidate.c_str());
json message = {{"type", "candidate"}, {"sdp", candidate}};
send_msg(offer_hdl_map_[transport_id], message);
break;
}
default:
break;
}
}
// std::string sdp = j["sdp"];
// LOG_INFO("Message type: {}", type);
// LOG_INFO("Message body: {}", sdp);
// server_.send(hdl, msg->get_payload(), msg->get_opcode());
}

View File

@@ -0,0 +1,50 @@
#ifndef _SIGNAL_SERVER_H_
#define _SIGNAL_SERVER_H_
#include <functional>
#include <map>
#include <nlohmann/json.hpp>
#include <string>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
using nlohmann::json;
typedef websocketpp::server<websocketpp::config::asio> server;
typedef unsigned int connection_id;
typedef std::string room_id;
class SignalServer {
public:
SignalServer();
~SignalServer();
bool on_open(websocketpp::connection_hdl hdl);
bool on_close(websocketpp::connection_hdl hdl);
bool on_ping(websocketpp::connection_hdl hdl, std::string s);
bool on_pong(websocketpp::connection_hdl hdl, std::string s);
void run();
void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg);
void send_msg(websocketpp::connection_hdl hdl, json message);
private:
server server_;
std::map<websocketpp::connection_hdl, connection_id,
std::owner_less<websocketpp::connection_hdl>>
connections_;
std::map<room_id, connection_id> rooms_;
unsigned int connection_id_ = 0;
std::string transport_id_ = "000000";
std::map<std::string, std::string> offer_sdp_map_;
std::map<std::string, std::string> answer_sdp_map_;
std::map<std::string, websocketpp::connection_hdl> offer_hdl_map_;
std::map<std::string, websocketpp::connection_hdl> answer_hdl_map_;
};
#endif

View File

@@ -0,0 +1,176 @@
/**
* Copyright (c) 2020-2022 Paul-Louis Ageneau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#ifndef JUICE_H
#define JUICE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef JUICE_HAS_EXPORT_HEADER
#include "juice_export.h"
#else // no export header
#ifdef JUICE_STATIC
#define JUICE_EXPORT
#else // dynamic library
#ifdef _WIN32
#if defined(JUICE_EXPORTS) || defined(juice_EXPORTS)
#define JUICE_EXPORT __declspec(dllexport) // building the library
#else
#define JUICE_EXPORT __declspec(dllimport) // using the library
#endif
#else // not WIN32
#define JUICE_EXPORT
#endif
#endif
#endif
#define JUICE_ERR_SUCCESS 0
#define JUICE_ERR_INVALID -1 // invalid argument
#define JUICE_ERR_FAILED -2 // runtime error
#define JUICE_ERR_NOT_AVAIL -3 // element not available
// ICE Agent
#define JUICE_MAX_ADDRESS_STRING_LEN 64
#define JUICE_MAX_CANDIDATE_SDP_STRING_LEN 256
#define JUICE_MAX_SDP_STRING_LEN 4096
typedef struct juice_agent juice_agent_t;
typedef enum juice_state {
JUICE_STATE_DISCONNECTED = 0,
JUICE_STATE_GATHERING,
JUICE_STATE_CONNECTING,
JUICE_STATE_CONNECTED,
JUICE_STATE_COMPLETED,
JUICE_STATE_FAILED
} juice_state_t;
typedef void (*juice_cb_state_changed_t)(juice_agent_t *agent, juice_state_t state, void *user_ptr);
typedef void (*juice_cb_candidate_t)(juice_agent_t *agent, const char *sdp, void *user_ptr);
typedef void (*juice_cb_gathering_done_t)(juice_agent_t *agent, void *user_ptr);
typedef void (*juice_cb_recv_t)(juice_agent_t *agent, const char *data, size_t size,
void *user_ptr);
typedef struct juice_turn_server {
const char *host;
const char *username;
const char *password;
uint16_t port;
} juice_turn_server_t;
typedef enum juice_concurrency_mode {
JUICE_CONCURRENCY_MODE_POLL = 0, // Connections share a single thread
JUICE_CONCURRENCY_MODE_MUX, // Connections are multiplexed on a single UDP socket
JUICE_CONCURRENCY_MODE_THREAD, // Each connection runs in its own thread
} juice_concurrency_mode_t;
typedef struct juice_config {
juice_concurrency_mode_t concurrency_mode;
const char *stun_server_host;
uint16_t stun_server_port;
juice_turn_server_t *turn_servers;
int turn_servers_count;
const char *bind_address;
uint16_t local_port_range_begin;
uint16_t local_port_range_end;
juice_cb_state_changed_t cb_state_changed;
juice_cb_candidate_t cb_candidate;
juice_cb_gathering_done_t cb_gathering_done;
juice_cb_recv_t cb_recv;
void *user_ptr;
} juice_config_t;
JUICE_EXPORT juice_agent_t *juice_create(const juice_config_t *config);
JUICE_EXPORT void juice_destroy(juice_agent_t *agent);
JUICE_EXPORT int juice_gather_candidates(juice_agent_t *agent);
JUICE_EXPORT int juice_get_local_description(juice_agent_t *agent, char *buffer, size_t size);
JUICE_EXPORT int juice_set_remote_description(juice_agent_t *agent, const char *sdp);
JUICE_EXPORT int juice_add_remote_candidate(juice_agent_t *agent, const char *sdp);
JUICE_EXPORT int juice_set_remote_gathering_done(juice_agent_t *agent);
JUICE_EXPORT int juice_send(juice_agent_t *agent, const char *data, size_t size);
JUICE_EXPORT int juice_send_diffserv(juice_agent_t *agent, const char *data, size_t size, int ds);
JUICE_EXPORT juice_state_t juice_get_state(juice_agent_t *agent);
JUICE_EXPORT int juice_get_selected_candidates(juice_agent_t *agent, char *local, size_t local_size,
char *remote, size_t remote_size);
JUICE_EXPORT int juice_get_selected_addresses(juice_agent_t *agent, char *local, size_t local_size,
char *remote, size_t remote_size);
JUICE_EXPORT const char *juice_state_to_string(juice_state_t state);
// ICE server
typedef struct juice_server juice_server_t;
typedef struct juice_server_credentials {
const char *username;
const char *password;
int allocations_quota;
} juice_server_credentials_t;
typedef struct juice_server_config {
juice_server_credentials_t *credentials;
int credentials_count;
int max_allocations;
int max_peers;
const char *bind_address;
const char *external_address;
uint16_t port;
uint16_t relay_port_range_begin;
uint16_t relay_port_range_end;
const char *realm;
} juice_server_config_t;
JUICE_EXPORT juice_server_t *juice_server_create(const juice_server_config_t *config);
JUICE_EXPORT void juice_server_destroy(juice_server_t *server);
JUICE_EXPORT uint16_t juice_server_get_port(juice_server_t *server);
JUICE_EXPORT int juice_server_add_credentials(juice_server_t *server,
const juice_server_credentials_t *credentials,
unsigned long lifetime_ms);
// Logging
typedef enum juice_log_level {
JUICE_LOG_LEVEL_VERBOSE = 0,
JUICE_LOG_LEVEL_DEBUG,
JUICE_LOG_LEVEL_INFO,
JUICE_LOG_LEVEL_WARN,
JUICE_LOG_LEVEL_ERROR,
JUICE_LOG_LEVEL_FATAL,
JUICE_LOG_LEVEL_NONE
} juice_log_level_t;
typedef void (*juice_log_cb_t)(juice_log_level_t level, const char *message);
JUICE_EXPORT void juice_set_log_level(juice_log_level_t level);
JUICE_EXPORT void juice_set_log_handler(juice_log_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif

BIN
thirdparty/libjuice/lib/juice.lib vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,28 @@
# - Config file for the websocketpp package
# It defines the following variables
# WEBSOCKETPP_FOUND - indicates that the module was found
# WEBSOCKETPP_INCLUDE_DIR - include directories
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was websocketpp-config.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
####################################################################################
set_and_check(WEBSOCKETPP_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
set(WEBSOCKETPP_FOUND TRUE)
#This is a bit of a hack, but it works well. It also allows continued support of CMake 2.8
if(${CMAKE_VERSION} VERSION_GREATER 3.0.0 OR ${CMAKE_VERSION} VERSION_EQUAL 3.0.0)
add_library(websocketpp::websocketpp INTERFACE IMPORTED)
set_target_properties(websocketpp::websocketpp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WEBSOCKETPP_INCLUDE_DIR}")
endif()

View File

@@ -0,0 +1,88 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is equal to the requested version.
# The tweak version component is ignored.
# The variable CVF_VERSION must be set before calling configure_file().
if (PACKAGE_FIND_VERSION_RANGE)
message(AUTHOR_WARNING
"`find_package()` specify a version range but the version strategy "
"(ExactVersion) of the module `${PACKAGE_FIND_NAME}` is incompatible "
"with this request. Only the lower endpoint of the range will be used.")
endif()
set(PACKAGE_VERSION "0.8.2")
if("0.8.2" MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") # strip the tweak version
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
set(CVF_VERSION_PATCH "${CMAKE_MATCH_3}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
if(NOT CVF_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MINOR "${CVF_VERSION_MINOR}")
endif()
if(NOT CVF_VERSION_PATCH VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_PATCH "${CVF_VERSION_PATCH}")
endif()
set(CVF_VERSION_NO_TWEAK "${CVF_VERSION_MAJOR}.${CVF_VERSION_MINOR}.${CVF_VERSION_PATCH}")
else()
set(CVF_VERSION_NO_TWEAK "0.8.2")
endif()
if(PACKAGE_FIND_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") # strip the tweak version
set(REQUESTED_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(REQUESTED_VERSION_MINOR "${CMAKE_MATCH_2}")
set(REQUESTED_VERSION_PATCH "${CMAKE_MATCH_3}")
if(NOT REQUESTED_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_MAJOR "${REQUESTED_VERSION_MAJOR}")
endif()
if(NOT REQUESTED_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_MINOR "${REQUESTED_VERSION_MINOR}")
endif()
if(NOT REQUESTED_VERSION_PATCH VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" REQUESTED_VERSION_PATCH "${REQUESTED_VERSION_PATCH}")
endif()
set(REQUESTED_VERSION_NO_TWEAK
"${REQUESTED_VERSION_MAJOR}.${REQUESTED_VERSION_MINOR}.${REQUESTED_VERSION_PATCH}")
else()
set(REQUESTED_VERSION_NO_TWEAK "${PACKAGE_FIND_VERSION}")
endif()
if(REQUESTED_VERSION_NO_TWEAK STREQUAL CVF_VERSION_NO_TWEAK)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
# if the installed project requested no architecture check, don't perform the check
if("FALSE")
return()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

View File

@@ -0,0 +1,178 @@
/*
******
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
*/
#ifndef _BASE64_HPP_
#define _BASE64_HPP_
#include <string>
namespace websocketpp {
static std::string const base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/// Test whether a character is a valid base64 character
/**
* @param c The character to test
* @return true if c is a valid base64 character
*/
static inline bool is_base64(unsigned char c) {
return (c == 43 || // +
(c >= 47 && c <= 57) || // /-9
(c >= 65 && c <= 90) || // A-Z
(c >= 97 && c <= 122)); // a-z
}
/// Encode a char buffer into a base64 string
/**
* @param input The input data
* @param len The length of input in bytes
* @return A base64 encoded string representing input
*/
inline std::string base64_encode(unsigned char const * input, size_t len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (len--) {
char_array_3[i++] = *(input++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +
((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +
((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++) {
ret += base64_chars[char_array_4[i]];
}
i = 0;
}
}
if (i) {
for(j = i; j < 3; j++) {
char_array_3[j] = '\0';
}
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +
((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +
((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++) {
ret += base64_chars[char_array_4[j]];
}
while((i++ < 3)) {
ret += '=';
}
}
return ret;
}
/// Encode a string into a base64 string
/**
* @param input The input data
* @return A base64 encoded string representing input
*/
inline std::string base64_encode(std::string const & input) {
return base64_encode(
reinterpret_cast<const unsigned char *>(input.data()),
input.size()
);
}
/// Decode a base64 encoded string into a string of raw bytes
/**
* @param input The base64 encoded input data
* @return A string representing the decoded raw bytes
*/
inline std::string base64_decode(std::string const & input) {
size_t in_len = input.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( input[in_] != '=') && is_base64(input[in_])) {
char_array_4[i++] = input[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++) {
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++) {
ret += char_array_3[i];
}
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) {
ret += static_cast<std::string::value_type>(char_array_3[j]);
}
}
return ret;
}
} // namespace websocketpp
#endif // _BASE64_HPP_

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2014, 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_CLIENT_HPP
#define WEBSOCKETPP_CLIENT_HPP
#include <websocketpp/roles/client_endpoint.hpp>
#endif //WEBSOCKETPP_CLIENT_HPP

View File

@@ -0,0 +1,353 @@
/*
* Copyright (c) 2014, 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_CLOSE_HPP
#define WEBSOCKETPP_CLOSE_HPP
/** \file
* A package of types and methods for manipulating WebSocket close codes.
*/
#include <websocketpp/error.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/utf8_validator.hpp>
#include <string>
namespace websocketpp {
/// A package of types and methods for manipulating WebSocket close codes.
namespace close {
/// A package of types and methods for manipulating WebSocket close status'
namespace status {
/// The type of a close code value.
typedef uint16_t value;
/// A blank value for internal use.
static value const blank = 0;
/// Close the connection without a WebSocket close handshake.
/**
* This special value requests that the WebSocket connection be closed
* without performing the WebSocket closing handshake. This does not comply
* with RFC6455, but should be safe to do if necessary. This could be useful
* for clients that need to disconnect quickly and cannot afford the
* complete handshake.
*/
static value const omit_handshake = 1;
/// Close the connection with a forced TCP drop.
/**
* This special value requests that the WebSocket connection be closed by
* forcibly dropping the TCP connection. This will leave the other side of
* the connection with a broken connection and some expensive timeouts. this
* should not be done except in extreme cases or in cases of malicious
* remote endpoints.
*/
static value const force_tcp_drop = 2;
/// Normal closure, meaning that the purpose for which the connection was
/// established has been fulfilled.
static value const normal = 1000;
/// The endpoint was "going away", such as a server going down or a browser
/// navigating away from a page.
static value const going_away = 1001;
/// A protocol error occurred.
static value const protocol_error = 1002;
/// The connection was terminated because an endpoint received a type of
/// data it cannot accept.
/**
* (e.g., an endpoint that understands only text data MAY send this if it
* receives a binary message).
*/
static value const unsupported_data = 1003;
/// A dummy value to indicate that no status code was received.
/**
* This value is illegal on the wire.
*/
static value const no_status = 1005;
/// A dummy value to indicate that the connection was closed abnormally.
/**
* In such a case there was no close frame to extract a value from. This
* value is illegal on the wire.
*/
static value const abnormal_close = 1006;
/// An endpoint received message data inconsistent with its type.
/**
* For example: Invalid UTF8 bytes in a text message.
*/
static value const invalid_payload = 1007;
/// An endpoint received a message that violated its policy.
/**
* This is a generic status code that can be returned when there is no other
* more suitable status code (e.g., 1003 or 1009) or if there is a need to
* hide specific details about the policy.
*/
static value const policy_violation = 1008;
/// An endpoint received a message too large to process.
static value const message_too_big = 1009;
/// A client expected the server to accept a required extension request
/**
* The list of extensions that are needed SHOULD appear in the /reason/ part
* of the Close frame. Note that this status code is not used by the server,
* because it can fail the WebSocket handshake instead.
*/
static value const extension_required = 1010;
/// An endpoint encountered an unexpected condition that prevented it from
/// fulfilling the request.
static value const internal_endpoint_error = 1011;
/// Indicates that the service is restarted. A client may reconnect and if
/// if it chooses to do so, should reconnect using a randomized delay of
/// 5-30s
static value const service_restart = 1012;
/// Indicates that the service is experiencing overload. A client should
/// only connect to a different IP (when there are multiple for the target)
/// or reconnect to the same IP upon user action.
static value const try_again_later = 1013;
/// Indicates that the server was acting as a gateway or proxy and received
/// an invalid response from the upstream server. This is similar to 502
/// HTTP Status Code.
static value const bad_gateway = 1014;
/// An endpoint failed to perform a TLS handshake
/**
* Designated for use in applications expecting a status code to indicate
* that the connection was closed due to a failure to perform a TLS
* handshake (e.g., the server certificate can't be verified). This value is
* illegal on the wire.
*/
static value const tls_handshake = 1015;
/// A generic subprotocol error
/**
* Indicates that a subprotocol error occurred. Typically this involves
* receiving a message that is not formatted as a valid message for the
* subprotocol in use.
*/
static value const subprotocol_error = 3000;
/// A invalid subprotocol data
/**
* Indicates that data was received that violated the specification of the
* subprotocol in use.
*/
static value const invalid_subprotocol_data = 3001;
/// First value in range reserved for future protocol use
static value const rsv_start = 1016;
/// Last value in range reserved for future protocol use
static value const rsv_end = 2999;
/// Test whether a close code is in a reserved range
/**
* @param [in] code The code to test
* @return Whether or not code is reserved
*/
inline bool reserved(value code) {
return ((code >= rsv_start && code <= rsv_end) ||
code == 1004);
}
/// First value in range that is always invalid on the wire
static value const invalid_low = 999;
/// Last value in range that is always invalid on the wire
static value const invalid_high = 5000;
/// Test whether a close code is invalid on the wire
/**
* @param [in] code The code to test
* @return Whether or not code is invalid on the wire
*/
inline bool invalid(value code) {
return (code <= invalid_low || code >= invalid_high ||
code == no_status || code == abnormal_close ||
code == tls_handshake);
}
/// Determine if the code represents an unrecoverable error
/**
* There is a class of errors for which once they are discovered normal
* WebSocket functionality can no longer occur. This function determines
* if a given code is one of these values. This information is used to
* determine if the system has the capability of waiting for a close
* acknowledgement or if it should drop the TCP connection immediately
* after sending its close frame.
*
* @param [in] code The value to test.
* @return True if the code represents an unrecoverable error
*/
inline bool terminal(value code) {
return (code == protocol_error || code == invalid_payload ||
code == policy_violation || code == message_too_big ||
code == internal_endpoint_error);
}
/// Return a human readable interpretation of a WebSocket close code
/**
* See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.
*
* @since 0.3.0
*
* @param [in] code The code to look up.
* @return A human readable interpretation of the code.
*/
inline std::string get_string(value code) {
switch (code) {
case normal:
return "Normal close";
case going_away:
return "Going away";
case protocol_error:
return "Protocol error";
case unsupported_data:
return "Unsupported data";
case no_status:
return "No status set";
case abnormal_close:
return "Abnormal close";
case invalid_payload:
return "Invalid payload";
case policy_violation:
return "Policy violoation";
case message_too_big:
return "Message too big";
case extension_required:
return "Extension required";
case internal_endpoint_error:
return "Internal endpoint error";
case service_restart:
return "Service restart";
case try_again_later:
return "Try again later";
case bad_gateway:
return "Bad gateway";
case tls_handshake:
return "TLS handshake failure";
case subprotocol_error:
return "Generic subprotocol error";
case invalid_subprotocol_data:
return "Invalid subprotocol data";
default:
return "Unknown";
}
}
} // namespace status
/// Type used to convert close statuses between integer and wire representations
union code_converter {
uint16_t i;
char c[2];
};
/// Extract a close code value from a close payload
/**
* If there is no close value (ie string is empty) status::no_status is
* returned. If a code couldn't be extracted (usually do to a short or
* otherwise mangled payload) status::protocol_error is returned and the ec
* value is flagged as an error. Note that this case is different than the case
* where protocol error is received over the wire.
*
* If the value is in an invalid or reserved range ec is set accordingly.
*
* @param [in] payload Close frame payload value received over the wire.
* @param [out] ec Set to indicate what error occurred, if any.
* @return The extracted value
*/
inline status::value extract_code(std::string const & payload, lib::error_code
& ec)
{
ec = lib::error_code();
if (payload.size() == 0) {
return status::no_status;
} else if (payload.size() == 1) {
ec = make_error_code(error::bad_close_code);
return status::protocol_error;
}
code_converter val;
val.c[0] = payload[0];
val.c[1] = payload[1];
status::value code(ntohs(val.i));
if (status::invalid(code)) {
ec = make_error_code(error::invalid_close_code);
}
if (status::reserved(code)) {
ec = make_error_code(error::reserved_close_code);
}
return code;
}
/// Extract the reason string from a close payload
/**
* The string should be a valid UTF8 message. error::invalid_utf8 will be set if
* the function extracts a reason that is not valid UTF8.
*
* @param [in] payload The payload string to extract a reason from.
* @param [out] ec Set to indicate what error occurred, if any.
* @return The reason string.
*/
inline std::string extract_reason(std::string const & payload, lib::error_code
& ec)
{
std::string reason;
ec = lib::error_code();
if (payload.size() > 2) {
reason.append(payload.begin()+2,payload.end());
}
if (!websocketpp::utf8_validator::validate(reason)) {
ec = make_error_code(error::invalid_utf8);
}
return reason;
}
} // namespace close
} // namespace websocketpp
#endif // WEBSOCKETPP_CLOSE_HPP

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2015, 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_COMMON_ASIO_HPP
#define WEBSOCKETPP_COMMON_ASIO_HPP
// This file goes to some length to preserve compatibility with versions of
// boost older than 1.49 (where the first modern steady_timer timer based on
// boost/std chrono was introduced.
//
// For the versions older than 1.49, the deadline_timer is used instead. this
// brings in dependencies on boost date_time and it has a different interface
// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds`
// wrappers provided by this file.
//
// The primary reason for this continued support is that boost 1.48 is the
// default and not easily changeable version of boost supplied by the package
// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need
// for this has passed this should be cleaned up and simplified.
#ifdef ASIO_STANDALONE
#include <asio/version.hpp>
#if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8
static_assert(false, "The minimum version of standalone Asio is 1.8.0");
#endif
#include <asio.hpp>
#include <asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#else
#include <boost/version.hpp>
// See note above about boost <1.49 compatibility. If we are running on
// boost > 1.48 pull in the steady timer and chrono library
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
#include <boost/asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#endif
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef ASIO_STANDALONE
namespace asio {
using namespace ::asio;
// Here we assume that we will be using std::error_code with standalone
// Asio. This is probably a good assumption, but it is possible in rare
// cases that local Asio versions would be used.
using std::errc;
// See note above about boost <1.49 compatibility. Because we require
// a standalone Asio version of 1.8+ we are guaranteed to have
// steady_timer available. By convention we require the chrono library
// (either boost or std) for use with standalone Asio.
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
} // namespace asio
#else
namespace asio {
using namespace boost::asio;
// See note above about boost <1.49 compatibility
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
// Using boost::asio >=1.49 so we use chrono and steady_timer
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
// If boost believes it has std::chrono available it will use it
// so we should also use it for things that relate to boost, even
// if the library would otherwise use boost::chrono.
#if defined(BOOST_ASIO_HAS_STD_CHRONO)
inline std::chrono::milliseconds milliseconds(long duration) {
return std::chrono::milliseconds(duration);
}
#else
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
#endif
#else
// Using boost::asio <1.49 we pretend a deadline timer is a steady
// timer and wrap the negative detection and duration conversion
// appropriately.
typedef boost::asio::deadline_timer steady_timer;
template <typename T>
bool is_neg(T duration) {
return duration.is_negative();
}
inline boost::posix_time::time_duration milliseconds(long duration) {
return boost::posix_time::milliseconds(duration);
}
#endif
using boost::system::error_code;
namespace errc = boost::system::errc;
} // namespace asio
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_ASIO_HPP

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2015, 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_COMMON_ASIO_SSL_HPP
#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP
// NOTE: This file must be included before common/asio.hpp
#ifdef ASIO_STANDALONE
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2015, 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_COMMON_CHRONO_HPP
#define WEBSOCKETPP_COMMON_CHRONO_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#endif
// If we're on Visual Studio 2012 or higher and haven't explicitly disabled
// the use of C++11 chrono header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
#include <chrono>
#else
#include <boost/chrono.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
namespace chrono = std::chrono;
#else
namespace chrono = boost::chrono;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_CHRONO_HPP

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2014, 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_COMMON_CONNECTION_HDL_HPP
#define WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP
#include <websocketpp/common/memory.hpp>
namespace websocketpp {
/// A handle to uniquely identify a connection.
/**
* This type uniquely identifies a connection. It is implemented as a weak
* pointer to the connection in question. This provides uniqueness across
* multiple endpoints and ensures that IDs never conflict or run out.
*
* It is safe to make copies of this handle, store those copies in containers,
* and use them from other threads.
*
* This handle can be upgraded to a full shared_ptr using
* `endpoint::get_con_from_hdl()` from within a handler fired by the connection
* that owns the handler.
*/
typedef lib::weak_ptr<void> connection_hdl;
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2014, 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_COMMON_CPP11_HPP
#define WEBSOCKETPP_COMMON_CPP11_HPP
/**
* This header sets up some constants based on the state of C++11 support
*/
// Hide clang feature detection from other compilers
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef __has_extension
#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
#endif
// The code below attempts to use information provided by the build system or
// user supplied defines to selectively enable C++11 language and library
// features. In most cases features that are targeted individually may also be
// selectively disabled via an associated _WEBSOCKETPP_NOXXX_ define.
#if defined(_WEBSOCKETPP_CPP11_STL_) || __cplusplus >= 201103L || defined(_WEBSOCKETPP_CPP11_STRICT_)
// This check tests for blanket c++11 coverage. It can be activated in one
// of three ways. Either the compiler itself reports that it is a full
// C++11 compiler via the __cplusplus macro or the user/build system
// supplies one of the two preprocessor defines below:
// This is defined to allow other WebSocket++ common headers to enable
// C++11 features when they are detected by this file rather than
// duplicating the above logic in every common header.
#define _WEBSOCKETPP_CPP11_INTERNAL_
// _WEBSOCKETPP_CPP11_STRICT_
//
// This define reports to WebSocket++ that 100% of the language and library
// features of C++11 are available. Using this define on a non-C++11
// compiler will result in problems.
// _WEBSOCKETPP_CPP11_STL_
//
// This define enables *most* C++11 options that were implemented early on
// by compilers. It is typically used for compilers that have many, but not
// all C++11 features. It should be safe to use on GCC 4.7-4.8 and perhaps
// earlier.
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#endif
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#endif
#ifndef _WEBSOCKETPP_INITIALIZER_LISTS_
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#endif
#ifndef _WEBSOCKETPP_MOVE_SEMANTICS_
#define _WEBSOCKETPP_MOVE_SEMANTICS_
#endif
#ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif
#ifndef __GNUC__
// GCC as of version 4.9 (latest) does not support std::put_time yet.
// so ignore it
#define _WEBSOCKETPP_PUTTIME_
#endif
#else
// In the absence of a blanket define, try to use compiler versions or
// feature testing macros to selectively enable what we can.
// Test for noexcept
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
#ifdef _WEBSOCKETPP_NOEXCEPT_
// build system says we have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#else
#if __has_feature(cxx_noexcept)
// clang feature detect says we have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#elif defined(_MSC_VER) && _MSC_VER >= 1900
// Visual Studio 2015+ has noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#else
// assume we don't have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
#endif
#endif
#endif
// Test for constexpr
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
#ifdef _WEBSOCKETPP_CONSTEXPR_
// build system says we have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#else
#if __has_feature(cxx_constexpr)
// clang feature detect says we have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#elif defined(_MSC_VER) && _MSC_VER >= 1900
// Visual Studio 2015+ has constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#else
// assume we don't have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_
#endif
#endif
#endif
// Enable initializer lists on clang when available.
#if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_)
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
// Test for nullptr
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
#ifdef _WEBSOCKETPP_NULLPTR_
// build system says we have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#else
#if __has_feature(cxx_nullptr)
// clang feature detect says we have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#elif defined(_MSC_VER) &&_MSC_VER >= 1600
// Visual Studio version that has nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#else
// assume we don't have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ 0
#endif
#endif
#endif
#endif
#endif // WEBSOCKETPP_COMMON_CPP11_HPP

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, 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_COMMON_FUNCTIONAL_HPP
#define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 functional header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#include <functional>
#else
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/ref.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
using std::function;
using std::bind;
using std::ref;
namespace placeholders = std::placeholders;
// There are some cases where a C++11 compiler balks at using std::ref
// but a C++03 compiler using boost function requires boost::ref. As such
// lib::ref is not useful in these cases. Instead this macro allows the use
// of boost::ref in the case of a boost compile or no reference wrapper at
// all in the case of a C++11 compile
#define _WEBSOCKETPP_REF(x) x
template <typename T>
void clear_function(T & x) {
x = nullptr;
}
#else
using boost::function;
using boost::bind;
using boost::ref;
namespace placeholders {
/// \todo this feels hacky, is there a better way?
using ::_1;
using ::_2;
using ::_3;
}
// See above definition for more details on what this is and why it exists
#define _WEBSOCKETPP_REF(x) boost::ref(x)
template <typename T>
void clear_function(T & x) {
x.clear();
}
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_FUNCTIONAL_HPP

View File

@@ -0,0 +1,448 @@
/*
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
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef WEBSOCKETPP_COMMON_MD5_HPP
#define WEBSOCKETPP_COMMON_MD5_HPP
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
#include <stddef.h>
#include <string>
#include <cstring>
namespace websocketpp {
/// Provides MD5 hashing functionality
namespace md5 {
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
/* Initialize the algorithm. */
inline void md5_init(md5_state_t *pms);
/* Append a string to the message. */
inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes);
/* Finish the message and return the digest. */
inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define ZSW_MD5_BYTE_ORDER 0
#endif
#define ZSW_MD5_T_MASK ((md5_word_t)~0)
#define ZSW_MD5_T1 /* 0xd76aa478 */ (ZSW_MD5_T_MASK ^ 0x28955b87)
#define ZSW_MD5_T2 /* 0xe8c7b756 */ (ZSW_MD5_T_MASK ^ 0x173848a9)
#define ZSW_MD5_T3 0x242070db
#define ZSW_MD5_T4 /* 0xc1bdceee */ (ZSW_MD5_T_MASK ^ 0x3e423111)
#define ZSW_MD5_T5 /* 0xf57c0faf */ (ZSW_MD5_T_MASK ^ 0x0a83f050)
#define ZSW_MD5_T6 0x4787c62a
#define ZSW_MD5_T7 /* 0xa8304613 */ (ZSW_MD5_T_MASK ^ 0x57cfb9ec)
#define ZSW_MD5_T8 /* 0xfd469501 */ (ZSW_MD5_T_MASK ^ 0x02b96afe)
#define ZSW_MD5_T9 0x698098d8
#define ZSW_MD5_T10 /* 0x8b44f7af */ (ZSW_MD5_T_MASK ^ 0x74bb0850)
#define ZSW_MD5_T11 /* 0xffff5bb1 */ (ZSW_MD5_T_MASK ^ 0x0000a44e)
#define ZSW_MD5_T12 /* 0x895cd7be */ (ZSW_MD5_T_MASK ^ 0x76a32841)
#define ZSW_MD5_T13 0x6b901122
#define ZSW_MD5_T14 /* 0xfd987193 */ (ZSW_MD5_T_MASK ^ 0x02678e6c)
#define ZSW_MD5_T15 /* 0xa679438e */ (ZSW_MD5_T_MASK ^ 0x5986bc71)
#define ZSW_MD5_T16 0x49b40821
#define ZSW_MD5_T17 /* 0xf61e2562 */ (ZSW_MD5_T_MASK ^ 0x09e1da9d)
#define ZSW_MD5_T18 /* 0xc040b340 */ (ZSW_MD5_T_MASK ^ 0x3fbf4cbf)
#define ZSW_MD5_T19 0x265e5a51
#define ZSW_MD5_T20 /* 0xe9b6c7aa */ (ZSW_MD5_T_MASK ^ 0x16493855)
#define ZSW_MD5_T21 /* 0xd62f105d */ (ZSW_MD5_T_MASK ^ 0x29d0efa2)
#define ZSW_MD5_T22 0x02441453
#define ZSW_MD5_T23 /* 0xd8a1e681 */ (ZSW_MD5_T_MASK ^ 0x275e197e)
#define ZSW_MD5_T24 /* 0xe7d3fbc8 */ (ZSW_MD5_T_MASK ^ 0x182c0437)
#define ZSW_MD5_T25 0x21e1cde6
#define ZSW_MD5_T26 /* 0xc33707d6 */ (ZSW_MD5_T_MASK ^ 0x3cc8f829)
#define ZSW_MD5_T27 /* 0xf4d50d87 */ (ZSW_MD5_T_MASK ^ 0x0b2af278)
#define ZSW_MD5_T28 0x455a14ed
#define ZSW_MD5_T29 /* 0xa9e3e905 */ (ZSW_MD5_T_MASK ^ 0x561c16fa)
#define ZSW_MD5_T30 /* 0xfcefa3f8 */ (ZSW_MD5_T_MASK ^ 0x03105c07)
#define ZSW_MD5_T31 0x676f02d9
#define ZSW_MD5_T32 /* 0x8d2a4c8a */ (ZSW_MD5_T_MASK ^ 0x72d5b375)
#define ZSW_MD5_T33 /* 0xfffa3942 */ (ZSW_MD5_T_MASK ^ 0x0005c6bd)
#define ZSW_MD5_T34 /* 0x8771f681 */ (ZSW_MD5_T_MASK ^ 0x788e097e)
#define ZSW_MD5_T35 0x6d9d6122
#define ZSW_MD5_T36 /* 0xfde5380c */ (ZSW_MD5_T_MASK ^ 0x021ac7f3)
#define ZSW_MD5_T37 /* 0xa4beea44 */ (ZSW_MD5_T_MASK ^ 0x5b4115bb)
#define ZSW_MD5_T38 0x4bdecfa9
#define ZSW_MD5_T39 /* 0xf6bb4b60 */ (ZSW_MD5_T_MASK ^ 0x0944b49f)
#define ZSW_MD5_T40 /* 0xbebfbc70 */ (ZSW_MD5_T_MASK ^ 0x4140438f)
#define ZSW_MD5_T41 0x289b7ec6
#define ZSW_MD5_T42 /* 0xeaa127fa */ (ZSW_MD5_T_MASK ^ 0x155ed805)
#define ZSW_MD5_T43 /* 0xd4ef3085 */ (ZSW_MD5_T_MASK ^ 0x2b10cf7a)
#define ZSW_MD5_T44 0x04881d05
#define ZSW_MD5_T45 /* 0xd9d4d039 */ (ZSW_MD5_T_MASK ^ 0x262b2fc6)
#define ZSW_MD5_T46 /* 0xe6db99e5 */ (ZSW_MD5_T_MASK ^ 0x1924661a)
#define ZSW_MD5_T47 0x1fa27cf8
#define ZSW_MD5_T48 /* 0xc4ac5665 */ (ZSW_MD5_T_MASK ^ 0x3b53a99a)
#define ZSW_MD5_T49 /* 0xf4292244 */ (ZSW_MD5_T_MASK ^ 0x0bd6ddbb)
#define ZSW_MD5_T50 0x432aff97
#define ZSW_MD5_T51 /* 0xab9423a7 */ (ZSW_MD5_T_MASK ^ 0x546bdc58)
#define ZSW_MD5_T52 /* 0xfc93a039 */ (ZSW_MD5_T_MASK ^ 0x036c5fc6)
#define ZSW_MD5_T53 0x655b59c3
#define ZSW_MD5_T54 /* 0x8f0ccc92 */ (ZSW_MD5_T_MASK ^ 0x70f3336d)
#define ZSW_MD5_T55 /* 0xffeff47d */ (ZSW_MD5_T_MASK ^ 0x00100b82)
#define ZSW_MD5_T56 /* 0x85845dd1 */ (ZSW_MD5_T_MASK ^ 0x7a7ba22e)
#define ZSW_MD5_T57 0x6fa87e4f
#define ZSW_MD5_T58 /* 0xfe2ce6e0 */ (ZSW_MD5_T_MASK ^ 0x01d3191f)
#define ZSW_MD5_T59 /* 0xa3014314 */ (ZSW_MD5_T_MASK ^ 0x5cfebceb)
#define ZSW_MD5_T60 0x4e0811a1
#define ZSW_MD5_T61 /* 0xf7537e82 */ (ZSW_MD5_T_MASK ^ 0x08ac817d)
#define ZSW_MD5_T62 /* 0xbd3af235 */ (ZSW_MD5_T_MASK ^ 0x42c50dca)
#define ZSW_MD5_T63 0x2ad7d2bb
#define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e)
static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if ZSW_MD5_BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
md5_word_t const * X;
#endif
{
#if ZSW_MD5_BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static int const w = 1;
if (*((md5_byte_t const *)&w)) /* dynamic little-endian */
#endif
#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (md5_byte_t const *)0) & 3)) {
/* data are properly aligned */
X = (md5_word_t const *)data;
} else {
/* not aligned */
std::memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if ZSW_MD5_BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if ZSW_MD5_BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ZSW_MD5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_F(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, ZSW_MD5_T1);
SET(d, a, b, c, 1, 12, ZSW_MD5_T2);
SET(c, d, a, b, 2, 17, ZSW_MD5_T3);
SET(b, c, d, a, 3, 22, ZSW_MD5_T4);
SET(a, b, c, d, 4, 7, ZSW_MD5_T5);
SET(d, a, b, c, 5, 12, ZSW_MD5_T6);
SET(c, d, a, b, 6, 17, ZSW_MD5_T7);
SET(b, c, d, a, 7, 22, ZSW_MD5_T8);
SET(a, b, c, d, 8, 7, ZSW_MD5_T9);
SET(d, a, b, c, 9, 12, ZSW_MD5_T10);
SET(c, d, a, b, 10, 17, ZSW_MD5_T11);
SET(b, c, d, a, 11, 22, ZSW_MD5_T12);
SET(a, b, c, d, 12, 7, ZSW_MD5_T13);
SET(d, a, b, c, 13, 12, ZSW_MD5_T14);
SET(c, d, a, b, 14, 17, ZSW_MD5_T15);
SET(b, c, d, a, 15, 22, ZSW_MD5_T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_G(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, ZSW_MD5_T17);
SET(d, a, b, c, 6, 9, ZSW_MD5_T18);
SET(c, d, a, b, 11, 14, ZSW_MD5_T19);
SET(b, c, d, a, 0, 20, ZSW_MD5_T20);
SET(a, b, c, d, 5, 5, ZSW_MD5_T21);
SET(d, a, b, c, 10, 9, ZSW_MD5_T22);
SET(c, d, a, b, 15, 14, ZSW_MD5_T23);
SET(b, c, d, a, 4, 20, ZSW_MD5_T24);
SET(a, b, c, d, 9, 5, ZSW_MD5_T25);
SET(d, a, b, c, 14, 9, ZSW_MD5_T26);
SET(c, d, a, b, 3, 14, ZSW_MD5_T27);
SET(b, c, d, a, 8, 20, ZSW_MD5_T28);
SET(a, b, c, d, 13, 5, ZSW_MD5_T29);
SET(d, a, b, c, 2, 9, ZSW_MD5_T30);
SET(c, d, a, b, 7, 14, ZSW_MD5_T31);
SET(b, c, d, a, 12, 20, ZSW_MD5_T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_H(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, ZSW_MD5_T33);
SET(d, a, b, c, 8, 11, ZSW_MD5_T34);
SET(c, d, a, b, 11, 16, ZSW_MD5_T35);
SET(b, c, d, a, 14, 23, ZSW_MD5_T36);
SET(a, b, c, d, 1, 4, ZSW_MD5_T37);
SET(d, a, b, c, 4, 11, ZSW_MD5_T38);
SET(c, d, a, b, 7, 16, ZSW_MD5_T39);
SET(b, c, d, a, 10, 23, ZSW_MD5_T40);
SET(a, b, c, d, 13, 4, ZSW_MD5_T41);
SET(d, a, b, c, 0, 11, ZSW_MD5_T42);
SET(c, d, a, b, 3, 16, ZSW_MD5_T43);
SET(b, c, d, a, 6, 23, ZSW_MD5_T44);
SET(a, b, c, d, 9, 4, ZSW_MD5_T45);
SET(d, a, b, c, 12, 11, ZSW_MD5_T46);
SET(c, d, a, b, 15, 16, ZSW_MD5_T47);
SET(b, c, d, a, 2, 23, ZSW_MD5_T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_I(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, ZSW_MD5_T49);
SET(d, a, b, c, 7, 10, ZSW_MD5_T50);
SET(c, d, a, b, 14, 15, ZSW_MD5_T51);
SET(b, c, d, a, 5, 21, ZSW_MD5_T52);
SET(a, b, c, d, 12, 6, ZSW_MD5_T53);
SET(d, a, b, c, 3, 10, ZSW_MD5_T54);
SET(c, d, a, b, 10, 15, ZSW_MD5_T55);
SET(b, c, d, a, 1, 21, ZSW_MD5_T56);
SET(a, b, c, d, 8, 6, ZSW_MD5_T57);
SET(d, a, b, c, 15, 10, ZSW_MD5_T58);
SET(c, d, a, b, 6, 15, ZSW_MD5_T59);
SET(b, c, d, a, 13, 21, ZSW_MD5_T60);
SET(a, b, c, d, 4, 6, ZSW_MD5_T61);
SET(d, a, b, c, 11, 10, ZSW_MD5_T62);
SET(c, d, a, b, 2, 15, ZSW_MD5_T63);
SET(b, c, d, a, 9, 21, ZSW_MD5_T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void md5_init(md5_state_t *pms) {
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ ZSW_MD5_T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) {
md5_byte_t const * p = data;
size_t left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));
std::memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
std::memcpy(pms->buf, p, left);
}
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {
static md5_byte_t const pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
// some convenience c++ functions
inline std::string md5_hash_string(std::string const & s) {
char digest[16];
md5_state_t state;
md5_init(&state);
md5_append(&state, (md5_byte_t const *)s.c_str(), s.size());
md5_finish(&state, (md5_byte_t *)digest);
std::string ret;
ret.resize(16);
std::copy(digest,digest+16,ret.begin());
return ret;
}
const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
inline std::string md5_hash_hex(std::string const & input) {
std::string hash = md5_hash_string(input);
std::string hex;
for (size_t i = 0; i < hash.size(); i++) {
hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);
hex.push_back(hexval[(hash[i]) & 0x0F]);
}
return hex;
}
} // md5
} // websocketpp
#endif // WEBSOCKETPP_COMMON_MD5_HPP

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2014, 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_COMMON_MEMORY_HPP
#define WEBSOCKETPP_COMMON_MEMORY_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 memory header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 functional header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
#include <memory>
#else
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/scoped_array.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/pointer_cast.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
using std::shared_ptr;
using std::weak_ptr;
using std::enable_shared_from_this;
using std::static_pointer_cast;
using std::make_shared;
using std::unique_ptr;
typedef std::unique_ptr<unsigned char[]> unique_ptr_uchar_array;
#else
using boost::shared_ptr;
using boost::weak_ptr;
using std::auto_ptr;
using boost::enable_shared_from_this;
using boost::static_pointer_cast;
using boost::make_shared;
typedef boost::scoped_array<unsigned char> unique_ptr_uchar_array;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_MEMORY_HPP

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2014, 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_COMMON_NETWORK_HPP
#define WEBSOCKETPP_COMMON_NETWORK_HPP
// For ntohs and htons
#if defined(_WIN32)
#include <winsock2.h>
#else
//#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
namespace lib {
namespace net {
inline bool is_little_endian() {
short int val = 0x1;
char *ptr = reinterpret_cast<char *>(&val);
return (ptr[0] == 1);
}
#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2
/// Convert 64 bit value to network byte order
/**
* This method is prefixed to avoid conflicts with operating system level
* macros for this functionality.
*
* TODO: figure out if it would be beneficial to use operating system level
* macros for this.
*
* @param src The integer in host byte order
* @return src converted to network byte order
*/
inline uint64_t _htonll(uint64_t src) {
static int typ = TYP_INIT;
unsigned char c;
union {
uint64_t ull;
unsigned char c[8];
} x;
if (typ == TYP_INIT) {
x.ull = 0x01;
typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
}
if (typ == TYP_BIGE)
return src;
x.ull = src;
c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
return x.ull;
}
/// Convert 64 bit value to host byte order
/**
* This method is prefixed to avoid conflicts with operating system level
* macros for this functionality.
*
* TODO: figure out if it would be beneficial to use operating system level
* macros for this.
*
* @param src The integer in network byte order
* @return src converted to host byte order
*/
inline uint64_t _ntohll(uint64_t src) {
return _htonll(src);
}
} // net
} // lib
} // websocketpp
#endif // WEBSOCKETPP_COMMON_NETWORK_HPP

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014, 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_COMMON_PLATFORMS_HPP
#define WEBSOCKETPP_COMMON_PLATFORMS_HPP
/**
* This header contains any platform specific preprocessor adjustments that
* don't fit somewhere else better.
*/
#if defined(_WIN32) && !defined(NOMINMAX)
// don't define min and max macros that conflict with std::min and std::max
#define NOMINMAX
#endif
// Bump up the variadic parameter max for Visual Studio 2012
#if defined(_MSC_VER) && _MSC_VER == 1700
#define _VARIADIC_MAX 8
#endif
#endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2014, 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_COMMON_RANDOM_DEVICE_HPP
#define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 random header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
#ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 random header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#include <random>
#else
#include <boost/version.hpp>
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 46
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/random_device.hpp>
#elif (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) >= 43
#include <boost/nondet_random.hpp>
#else
// TODO: static_assert(false, "Could not find a suitable random_device")
#endif
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
using std::random_device;
using std::uniform_int_distribution;
#else
using boost::random::random_device;
using boost::random::uniform_int_distribution;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2014, 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_COMMON_REGEX_HPP
#define WEBSOCKETPP_COMMON_REGEX_HPP
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_REGEX_
#ifndef _WEBSOCKETPP_CPP11_REGEX_
#define _WEBSOCKETPP_CPP11_REGEX_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_REGEX_
#include <regex>
#else
#include <boost/regex.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_REGEX_
using std::cmatch;
using std::regex;
using std::regex_match;
#else
using boost::cmatch;
using boost::regex;
using boost::regex_match;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_REGEX_HPP

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_COMMON_STDINT_HPP
#define WEBSOCKETPP_COMMON_STDINT_HPP
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#if defined (_WIN32) && defined (_MSC_VER) && (_MSC_VER < 1600)
#include <boost/cstdint.hpp>
using boost::int8_t;
using boost::int_least8_t;
using boost::int_fast8_t;
using boost::uint8_t;
using boost::uint_least8_t;
using boost::uint_fast8_t;
using boost::int16_t;
using boost::int_least16_t;
using boost::int_fast16_t;
using boost::uint16_t;
using boost::uint_least16_t;
using boost::uint_fast16_t;
using boost::int32_t;
using boost::int_least32_t;
using boost::int_fast32_t;
using boost::uint32_t;
using boost::uint_least32_t;
using boost::uint_fast32_t;
#ifndef BOOST_NO_INT64_T
using boost::int64_t;
using boost::int_least64_t;
using boost::int_fast64_t;
using boost::uint64_t;
using boost::uint_least64_t;
using boost::uint_fast64_t;
#endif
using boost::intmax_t;
using boost::uintmax_t;
#else
#include <stdint.h>
#endif
#endif // WEBSOCKETPP_COMMON_STDINT_HPP

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2014, 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_COMMON_SYSTEM_ERROR_HPP
#define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 system_error header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 system_error header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#include <system_error>
#else
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
using std::errc;
using std::error_code;
using std::error_category;
using std::error_condition;
using std::system_error;
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }
#else
namespace errc = boost::system::errc;
using boost::system::error_code;
using boost::system::error_category;
using boost::system::error_condition;
using boost::system::system_error;
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace boost { namespace system {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }}
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2015, 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_COMMON_THREAD_HPP
#define WEBSOCKETPP_COMMON_THREAD_HPP
#include <websocketpp/common/cpp11.hpp>
// If we autodetect C++11 and haven't been explicitly instructed to not use
// C++11 threads, then set the defines that instructs the rest of this header
// to use C++11 <thread> and <mutex>
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
// MinGW by default does not support C++11 thread/mutex so even if the
// internal check for C++11 passes, ignore it if we are on MinGW
#if (!defined(__MINGW32__) && !defined(__MINGW64__))
#ifndef _WEBSOCKETPP_CPP11_THREAD_
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
#endif
#endif
// If we're on Visual Studio 2013 or higher and haven't explicitly disabled
// the use of C++11 thread header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1800 && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
#ifndef _WEBSOCKETPP_CPP11_THREAD_
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
#endif
#if defined(_WEBSOCKETPP_MINGW_THREAD_)
#include <mingw-threads/mingw.thread.h>
#include <mingw-threads/mingw.mutex.h>
#include <mingw-threads/mingw.condition_variable.h>
#elif defined(_WEBSOCKETPP_CPP11_THREAD_)
#include <thread>
#include <mutex>
#include <condition_variable>
#else
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#endif
namespace websocketpp {
namespace lib {
#if defined(_WEBSOCKETPP_CPP11_THREAD_) || defined(_WEBSOCKETPP_MINGW_THREAD_)
using std::mutex;
using std::lock_guard;
using std::thread;
using std::unique_lock;
using std::condition_variable;
#else
using boost::mutex;
using boost::lock_guard;
using boost::thread;
using boost::unique_lock;
using boost::condition_variable;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_THREAD_HPP

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, 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_COMMON_TIME_HPP
#define WEBSOCKETPP_COMMON_TIME_HPP
#include <ctime>
namespace websocketpp {
namespace lib {
// Code in this header was inspired by the following article and includes some
// code from the related project g2log. The g2log code is public domain licensed
// http://kjellkod.wordpress.com/2013/01/22/exploring-c11-part-2-localtime-and-time-again/
/// Thread safe cross platform localtime
inline std::tm localtime(std::time_t const & time) {
std::tm tm_snapshot;
#if (defined(__MINGW32__) || defined(__MINGW64__))
memcpy(&tm_snapshot, ::localtime(&time), sizeof(std::tm));
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_s(&tm_snapshot, &time);
#else
localtime_r(&time, &tm_snapshot); // POSIX
#endif
return tm_snapshot;
}
} // lib
} // websocketpp
#endif // WEBSOCKETPP_COMMON_TIME_HPP

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2015, 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_COMMON_TYPE_TRAITS_HPP
#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_TYPE_TRAITS_
#ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#include <type_traits>
#else
#include <boost/aligned_storage.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
using std::aligned_storage;
using std::is_same;
#else
using boost::aligned_storage;
using boost::is_same;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2014, 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_CONCURRENCY_BASIC_HPP
#define WEBSOCKETPP_CONCURRENCY_BASIC_HPP
#include <websocketpp/common/thread.hpp>
namespace websocketpp {
namespace concurrency {
/// Concurrency policy that uses std::mutex / boost::mutex
class basic {
public:
typedef lib::mutex mutex_type;
typedef lib::lock_guard<mutex_type> scoped_lock_type;
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, 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_CONCURRENCY_NONE_HPP
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
namespace websocketpp {
/// Concurrency handling support
namespace concurrency {
/// Implementation for no-op locking primitives
namespace none_impl {
/// A fake mutex implementation that does nothing
class fake_mutex {
public:
fake_mutex() {}
~fake_mutex() {}
};
/// A fake lock guard implementation that does nothing
class fake_lock_guard {
public:
explicit fake_lock_guard(fake_mutex) {}
~fake_lock_guard() {}
};
} // namespace none_impl
/// Stub concurrency policy that implements the interface using no-ops.
/**
* This policy documents the concurrency policy interface using no-ops. It can
* be used as a reference or base for building a new concurrency policy. It can
* also be used as is to disable all locking for endpoints used in purely single
* threaded programs.
*/
class none {
public:
/// The type of a mutex primitive
/**
* std::mutex is an example.
*/
typedef none_impl::fake_mutex mutex_type;
/// The type of a scoped/RAII lock primitive.
/**
* The scoped lock constructor should take a mutex_type as a parameter,
* acquire that lock, and release it in its destructor. std::lock_guard is
* an example.
*/
typedef none_impl::fake_lock_guard scoped_lock_type;
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_ASYNC_HPP

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_HPP
#include <websocketpp/config/core.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/asio_no_tls.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Server config with asio transport and TLS enabled
struct asio_tls : public core {
typedef asio_tls type;
typedef core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_HPP

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP
#include <websocketpp/config/core_client.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/asio_no_tls_client.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Client config with asio transport and TLS enabled
struct asio_tls_client : public core_client {
typedef asio_tls_client type;
typedef core_client base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_HPP
#define WEBSOCKETPP_CONFIG_ASIO_HPP
#include <websocketpp/config/core.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Server config with asio transport and TLS disabled
struct asio : public core {
typedef asio type;
typedef core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_HPP

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP
#include <websocketpp/config/core_client.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Client config with asio transport and TLS disabled
struct asio_client : public core_client {
typedef asio_client type;
typedef core_client base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, 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.
*
*/
// This header defines WebSocket++ macros for C++11 compatibility based on the
// Boost.Config library. This will correctly configure most target platforms
// simply by including this header before any other WebSocket++ header.
#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
#include <boost/config.hpp>
// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently
// only work if either both or neither is defined.
#if !defined BOOST_NO_CXX11_SMART_PTR && !defined BOOST_NO_CXX11_HDR_FUNCTIONAL
#define _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#ifdef BOOST_ASIO_HAS_STD_CHRONO
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#ifndef BOOST_NO_CXX11_HDR_RANDOM
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#endif
#ifndef BOOST_NO_CXX11_HDR_REGEX
#define _WEBSOCKETPP_CPP11_REGEX_
#endif
#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#ifndef BOOST_NO_CXX11_HDR_THREAD
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR
// TODO: nullptr support
#endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP

View File

@@ -0,0 +1,297 @@
/*
* Copyright (c) 2014, 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_CONFIG_CORE_HPP
#define WEBSOCKETPP_CONFIG_CORE_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/basic.hpp>
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/logger/levels.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Server config with iostream transport
struct core {
typedef core type;
// Concurrency policy
typedef websocketpp::concurrency::basic concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
/// Size of the per-connection read buffer
/**
* Each connection has an internal buffer of this size. A larger value will
* result in fewer trips through the library and less CPU overhead at the
* expense of increased memory usage per connection.
*
* If your application primarily deals in very large messages you may want
* to try setting this value higher.
*
* If your application has a lot of connections or primarily deals in small
* messages you may want to try setting this smaller.
*/
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef core::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_HPP

View File

@@ -0,0 +1,294 @@
/*
* Copyright (c) 2014, 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_CONFIG_CORE_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#ifndef _WEBSOCKETPP_NO_THREADING_
#include <websocketpp/concurrency/basic.hpp>
#else
#include <websocketpp/concurrency/none.hpp>
#endif
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
// RNG
#include <websocketpp/random/random_device.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Client config with iostream transport
struct core_client {
typedef core_client type;
// Concurrency policy
#ifndef _WEBSOCKETPP_NO_THREADING_
typedef websocketpp::concurrency::basic concurrency_type;
#else
typedef websocketpp::concurrency::none concurrency_type;
#endif
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::random_device::int_generator<uint32_t,
concurrency_type> rng_type;
/// Controls compile time enabling/disabling of thread syncronization code
/// Disabling can provide a minor performance improvement to single threaded
/// applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_deflate extension
struct permessage_deflate_config {
typedef core_client::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-compress
/**
* Automatically enables the permessage-compress extension.
*
* For clients this results in a permessage-compress extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP

View File

@@ -0,0 +1,286 @@
/*
* Copyright (c) 2014, 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_CONFIG_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_DEBUG_HPP
// Non-Policy common stuff
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/basic.hpp>
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Client/Server debug config with iostream transport
struct debug_core {
typedef debug_core type;
// Concurrency policy
typedef websocketpp::concurrency::basic concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef type::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_HPP

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP
#include <websocketpp/config/debug.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/debug_asio_no_tls.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Client/Server debug config with asio transport and TLS enabled
struct debug_asio_tls : public debug_core {
typedef debug_asio_tls type;
typedef debug_core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP
#include <websocketpp/config/debug.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Client/Server debug config with asio transport and TLS disabled
struct debug_asio : public debug_core {
typedef debug_asio type;
typedef debug_core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, 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_CONFIG_MINIMAL_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP
#include <websocketpp/config/minimal_server.hpp>
namespace websocketpp {
namespace config {
/// Client config with minimal dependencies
/**
* This config strips out as many dependencies as possible. It is suitable for
* use as a base class for custom configs that want to implement or choose their
* own policies for components that even the core config includes.
*
* NOTE: this config stubs out enough that it cannot be used directly. You must
* supply at least a transport policy and a cryptographically secure random
* number generation policy for a config based on `minimal_client` to do
* anything useful.
*
* Present dependency list for minimal_server config:
*
* C++98 STL:
* <algorithm>
* <map>
* <sstream>
* <string>
* <vector>
*
* C++11 STL or Boost
* <memory>
* <functional>
* <system_error>
*
* Operating System:
* <stdint.h> or <boost/cstdint.hpp>
* <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)
*
* @since 0.4.0-dev
*/
typedef minimal_server minimal_client;
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 2014, 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_CONFIG_MINIMAL_HPP
#define WEBSOCKETPP_CONFIG_MINIMAL_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/none.hpp>
// Transport
#include <websocketpp/transport/stub/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/stub.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Server config with minimal dependencies
/**
* This config strips out as many dependencies as possible. It is suitable for
* use as a base class for custom configs that want to implement or choose their
* own policies for components that even the core config includes.
*
* NOTE: this config stubs out enough that it cannot be used directly. You must
* supply at least a transport policy for a config based on `minimal_server` to
* do anything useful.
*
* Present dependency list for minimal_server config:
*
* C++98 STL:
* <algorithm>
* <map>
* <sstream>
* <string>
* <vector>
*
* C++11 STL or Boost
* <memory>
* <functional>
* <system_error>
*
* Operating System:
* <stdint.h> or <boost/cstdint.hpp>
* <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)
*
* @since 0.4.0-dev
*/
struct minimal_server {
typedef minimal_server type;
// Concurrency policy
typedef websocketpp::concurrency::none concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::stub elog_type;
typedef websocketpp::log::stub alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::stub::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::none;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::none;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.4.0-alpha1
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef core::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_MINIMAL_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2014, 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_CONNECTION_BASE_HPP
#define WEBSOCKETPP_CONNECTION_BASE_HPP
namespace websocketpp {
/// Stub for user supplied base class.
class connection_base {};
} // namespace websocketpp
#endif // WEBSOCKETPP_CONNECTION_BASE_HPP

View File

@@ -0,0 +1,700 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_HPP
#define WEBSOCKETPP_ENDPOINT_HPP
#include <websocketpp/connection.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/version.hpp>
#include <string>
namespace websocketpp {
/// Creates and manages connections associated with a WebSocket endpoint
template <typename connection, typename config>
class endpoint : public config::transport_type, public config::endpoint_base {
public:
// Import appropriate types from our helper class
// See endpoint_types for more details.
typedef endpoint<connection,config> type;
/// Type of the transport component of this endpoint
typedef typename config::transport_type transport_type;
/// Type of the concurrency component of this endpoint
typedef typename config::concurrency_type concurrency_type;
/// Type of the connections that this endpoint creates
typedef connection connection_type;
/// Shared pointer to connection_type
typedef typename connection_type::ptr connection_ptr;
/// Weak pointer to connection type
typedef typename connection_type::weak_ptr connection_weak_ptr;
/// Type of the transport component of the connections that this endpoint
/// creates
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the transport component of the connections
/// that this endpoint creates.
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of message_handler
typedef typename connection_type::message_handler message_handler;
/// Type of message pointers that this endpoint uses
typedef typename connection_type::message_ptr message_ptr;
/// Type of error logger
typedef typename config::elog_type elog_type;
/// Type of access logger
typedef typename config::alog_type alog_type;
/// Type of our concurrency policy's scoped lock object
typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
/// Type of our concurrency policy's mutex object
typedef typename concurrency_type::mutex_type mutex_type;
/// Type of RNG
typedef typename config::rng_type rng_type;
// TODO: organize these
typedef typename connection_type::termination_handler termination_handler;
// This would be ideal. Requires C++11 though
//friend connection;
explicit endpoint(bool p_is_server)
: m_alog(new alog_type(config::alog_level, log::channel_type_hint::access))
, m_elog(new elog_type(config::elog_level, log::channel_type_hint::error))
, m_user_agent(::websocketpp::user_agent)
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
, m_pong_timeout_dur(config::timeout_pong)
, m_max_message_size(config::max_message_size)
, m_max_http_body_size(config::max_http_body_size)
, m_is_server(p_is_server)
{
m_alog->set_channels(config::alog_level);
m_elog->set_channels(config::elog_level);
m_alog->write(log::alevel::devel, "endpoint constructor");
transport_type::init_logging(m_alog, m_elog);
}
/// Destructor
~endpoint<connection,config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
endpoint(endpoint &) = delete;
// no copy assignment operator because endpoints are not copyable
endpoint & operator=(endpoint const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
endpoint(endpoint && o)
: config::transport_type(std::move(o))
, config::endpoint_base(std::move(o))
, m_alog(std::move(o.m_alog))
, m_elog(std::move(o.m_elog))
, m_user_agent(std::move(o.m_user_agent))
, m_open_handler(std::move(o.m_open_handler))
, m_close_handler(std::move(o.m_close_handler))
, m_fail_handler(std::move(o.m_fail_handler))
, m_ping_handler(std::move(o.m_ping_handler))
, m_pong_handler(std::move(o.m_pong_handler))
, m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))
, m_interrupt_handler(std::move(o.m_interrupt_handler))
, m_http_handler(std::move(o.m_http_handler))
, m_validate_handler(std::move(o.m_validate_handler))
, m_message_handler(std::move(o.m_message_handler))
, m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)
, m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)
, m_pong_timeout_dur(o.m_pong_timeout_dur)
, m_max_message_size(o.m_max_message_size)
, m_max_http_body_size(o.m_max_http_body_size)
, m_rng(std::move(o.m_rng))
, m_is_server(o.m_is_server)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
endpoint & operator=(endpoint &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Returns the user agent string that this endpoint will use
/**
* Returns the user agent string that this endpoint will use when creating
* new connections.
*
* The default value for this version is stored in websocketpp::user_agent
*
* @return The user agent string.
*/
std::string get_user_agent() const {
scoped_lock_type guard(m_mutex);
return m_user_agent;
}
/// Sets the user agent string that this endpoint will use
/**
* Sets the identifier that this endpoint will use when creating new
* connections. Changing this value will only affect future connections.
* For client endpoints this will be sent as the "User-Agent" header in
* outgoing requests. For server endpoints this will be sent in the "Server"
* response header.
*
* Setting this value to the empty string will suppress the use of the
* Server and User-Agent headers. This is typically done to hide
* implementation details for security purposes.
*
* For best results set this before accepting or opening connections.
*
* The default value for this version is stored in websocketpp::user_agent
*
* This can be overridden on an individual connection basis by setting a
* custom "Server" header during the validate handler or "User-Agent"
* header on a connection before calling connect().
*
* @param ua The string to set the user agent to.
*/
void set_user_agent(std::string const & ua) {
scoped_lock_type guard(m_mutex);
m_user_agent = ua;
}
/// Returns whether or not this endpoint is a server.
/**
* @return Whether or not this endpoint is a server
*/
bool is_server() const {
return m_is_server;
}
/********************************/
/* Pass-through logging adaptor */
/********************************/
/// Set Access logging channel
/**
* Set the access logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to set
*/
void set_access_channels(log::level channels) {
m_alog->set_channels(channels);
}
/// Clear Access logging channels
/**
* Clear the access logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to clear
*/
void clear_access_channels(log::level channels) {
m_alog->clear_channels(channels);
}
/// Set Error logging channel
/**
* Set the error logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to set
*/
void set_error_channels(log::level channels) {
m_elog->set_channels(channels);
}
/// Clear Error logging channels
/**
* Clear the error logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to clear
*/
void clear_error_channels(log::level channels) {
m_elog->clear_channels(channels);
}
/// Get reference to access logger
/**
* @return A reference to the access logger
*/
alog_type & get_alog() {
return *m_alog;
}
/// Get reference to error logger
/**
* @return A reference to the error logger
*/
elog_type & get_elog() {
return *m_elog;
}
/*************************/
/* Set Handler functions */
/*************************/
void set_open_handler(open_handler h) {
m_alog->write(log::alevel::devel,"set_open_handler");
scoped_lock_type guard(m_mutex);
m_open_handler = h;
}
void set_close_handler(close_handler h) {
m_alog->write(log::alevel::devel,"set_close_handler");
scoped_lock_type guard(m_mutex);
m_close_handler = h;
}
void set_fail_handler(fail_handler h) {
m_alog->write(log::alevel::devel,"set_fail_handler");
scoped_lock_type guard(m_mutex);
m_fail_handler = h;
}
void set_ping_handler(ping_handler h) {
m_alog->write(log::alevel::devel,"set_ping_handler");
scoped_lock_type guard(m_mutex);
m_ping_handler = h;
}
void set_pong_handler(pong_handler h) {
m_alog->write(log::alevel::devel,"set_pong_handler");
scoped_lock_type guard(m_mutex);
m_pong_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);
m_pong_timeout_handler = h;
}
void set_interrupt_handler(interrupt_handler h) {
m_alog->write(log::alevel::devel,"set_interrupt_handler");
scoped_lock_type guard(m_mutex);
m_interrupt_handler = h;
}
void set_http_handler(http_handler h) {
m_alog->write(log::alevel::devel,"set_http_handler");
scoped_lock_type guard(m_mutex);
m_http_handler = h;
}
void set_validate_handler(validate_handler h) {
m_alog->write(log::alevel::devel,"set_validate_handler");
scoped_lock_type guard(m_mutex);
m_validate_handler = h;
}
void set_message_handler(message_handler h) {
m_alog->write(log::alevel::devel,"set_message_handler");
scoped_lock_type guard(m_mutex);
m_message_handler = h;
}
//////////////////////////////////////////
// Connection timeouts and other limits //
//////////////////////////////////////////
/// Set open handshake timeout
/**
* Sets the length of time the library will wait after an opening handshake
* has been initiated before cancelling it. This can be used to prevent
* excessive wait times for outgoing clients or excessive resource usage
* from broken clients or DoS attacks on servers.
*
* Connections that time out will have their fail handlers called with the
* open_handshake_timeout error code.
*
* The default value is specified via the compile time config value
* 'timeout_open_handshake'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the open handshake timeout in ms
*/
void set_open_handshake_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_open_handshake_timeout_dur = dur;
}
/// Set close handshake timeout
/**
* Sets the length of time the library will wait after a closing handshake
* has been initiated before cancelling it. This can be used to prevent
* excessive wait times for outgoing clients or excessive resource usage
* from broken clients or DoS attacks on servers.
*
* Connections that time out will have their close handlers called with the
* close_handshake_timeout error code.
*
* The default value is specified via the compile time config value
* 'timeout_close_handshake'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the close handshake timeout in ms
*/
void set_close_handshake_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_close_handshake_timeout_dur = dur;
}
/// Set pong timeout
/**
* Sets the length of time the library will wait for a pong response to a
* ping. This can be used as a keepalive or to detect broken connections.
*
* Pong responses that time out will have the pong timeout handler called.
*
* The default value is specified via the compile time config value
* 'timeout_pong'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the pong timeout in ms
*/
void set_pong_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_pong_timeout_dur = dur;
}
/// Get default maximum message size
/**
* Get the default maximum message size that will be used for new
* connections created by this endpoint. The maximum message size determines
* the point at which the connection will fail a connection with the
* message_too_big protocol error.
*
* The default is set by the max_message_size value from the template config
*
* @since 0.3.0
*/
size_t get_max_message_size() const {
return m_max_message_size;
}
/// Set default maximum message size
/**
* Set the default maximum message size that will be used for new
* connections created by this endpoint. Maximum message size determines the
* point at which the connection will fail a connection with the
* message_too_big protocol error.
*
* The default is set by the max_message_size value from the template config
*
* @since 0.3.0
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_message_size(size_t new_value) {
m_max_message_size = new_value;
}
/// Get maximum HTTP message body size
/**
* Get maximum HTTP message body size. Maximum message body size determines
* the point at which the connection will stop reading an HTTP request whose
* body is too large.
*
* The default is set by the max_http_body_size value from the template
* config
*
* @since 0.5.0
*
* @return The maximum HTTP message body size
*/
size_t get_max_http_body_size() const {
return m_max_http_body_size;
}
/// Set maximum HTTP message body size
/**
* Set maximum HTTP message body size. Maximum message body size determines
* the point at which the connection will stop reading an HTTP request whose
* body is too large.
*
* The default is set by the max_http_body_size value from the template
* config
*
* @since 0.5.1
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_http_body_size(size_t new_value) {
m_max_http_body_size = new_value;
}
/*************************************/
/* Connection pass through functions */
/*************************************/
/**
* These functions act as adaptors to their counterparts in connection. They
* can produce one additional type of error, the bad_connection error, that
* indicates that the conversion from connection_hdl to connection_ptr
* failed due to the connection not existing anymore. Each method has a
* default and an exception free varient.
*/
void interrupt(connection_hdl hdl, lib::error_code & ec);
void interrupt(connection_hdl hdl);
/// Pause reading of new data (exception free)
/**
* Signals to the connection to halt reading of new data. While reading is
* paused, the connection will stop reading from its associated socket. In
* turn this will result in TCP based flow control kicking in and slowing
* data flow from the remote endpoint.
*
* This is useful for applications that push new requests to a queue to be
* processed by another thread and need a way to signal when their request
* queue is full without blocking the network processing thread.
*
* Use `resume_reading()` to resume.
*
* If supported by the transport this is done asynchronously. As such
* reading may not stop until the current read operation completes.
* Typically you can expect to receive no more bytes after initiating a read
* pause than the size of the read buffer.
*
* If reading is paused for this connection already nothing is changed.
*/
void pause_reading(connection_hdl hdl, lib::error_code & ec);
/// Pause reading of new data
void pause_reading(connection_hdl hdl);
/// Resume reading of new data (exception free)
/**
* Signals to the connection to resume reading of new data after it was
* paused by `pause_reading()`.
*
* If reading is not paused for this connection already nothing is changed.
*/
void resume_reading(connection_hdl hdl, lib::error_code & ec);
/// Resume reading of new data
void resume_reading(connection_hdl hdl);
/// Send deferred HTTP Response
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception free variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
* @param ec A status code, zero on success, non-zero otherwise
*/
void send_http_response(connection_hdl hdl, lib::error_code & ec);
/// Send deferred HTTP Response (exception free)
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
*/
void send_http_response(connection_hdl hdl);
/// Create a message and add it to the outgoing send queue (exception free)
/**
* Convenience method to send a message given a payload string and an opcode
*
* @param [in] hdl The handle identifying the connection to send via.
* @param [in] payload The payload string to generated the message with
* @param [in] op The opcode to generated the message with.
* @param [out] ec A code to fill in for errors
*/
void send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op, lib::error_code & ec);
/// Create a message and add it to the outgoing send queue
/**
* Convenience method to send a message given a payload string and an opcode
*
* @param [in] hdl The handle identifying the connection to send via.
* @param [in] payload The payload string to generated the message with
* @param [in] op The opcode to generated the message with.
* @param [out] ec A code to fill in for errors
*/
void send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op);
void send(connection_hdl hdl, void const * payload, size_t len,
frame::opcode::value op, lib::error_code & ec);
void send(connection_hdl hdl, void const * payload, size_t len,
frame::opcode::value op);
void send(connection_hdl hdl, message_ptr msg, lib::error_code & ec);
void send(connection_hdl hdl, message_ptr msg);
void close(connection_hdl hdl, close::status::value const code,
std::string const & reason, lib::error_code & ec);
void close(connection_hdl hdl, close::status::value const code,
std::string const & reason);
/// Send a ping to a specific connection
/**
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
* @param [out] ec A reference to an error code to fill in
*/
void ping(connection_hdl hdl, std::string const & payload,
lib::error_code & ec);
/// Send a ping to a specific connection
/**
* Exception variant of `ping`
*
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
*/
void ping(connection_hdl hdl, std::string const & payload);
/// Send a pong to a specific connection
/**
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
* @param [out] ec A reference to an error code to fill in
*/
void pong(connection_hdl hdl, std::string const & payload,
lib::error_code & ec);
/// Send a pong to a specific connection
/**
* Exception variant of `pong`
*
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
*/
void pong(connection_hdl hdl, std::string const & payload);
/// Retrieves a connection_ptr from a connection_hdl (exception free)
/**
* Converting a weak pointer to shared_ptr is not thread safe because the
* pointer could be deleted at any time.
*
* NOTE: This method may be called by handler to upgrade its handle to a
* full connection_ptr. That full connection may then be used safely for the
* remainder of the handler body. get_con_from_hdl and the resulting
* connection_ptr are NOT safe to use outside the handler loop.
*
* @param hdl The connection handle to translate
*
* @return the connection_ptr. May be NULL if the handle was invalid.
*/
connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {
connection_ptr con = lib::static_pointer_cast<connection_type>(
hdl.lock());
if (!con) {
ec = error::make_error_code(error::bad_connection);
}
return con;
}
/// Retrieves a connection_ptr from a connection_hdl (exception version)
connection_ptr get_con_from_hdl(connection_hdl hdl) {
lib::error_code ec;
connection_ptr con = this->get_con_from_hdl(hdl,ec);
if (ec) {
throw exception(ec);
}
return con;
}
protected:
connection_ptr create_connection();
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
private:
// dynamic settings
std::string m_user_agent;
open_handler m_open_handler;
close_handler m_close_handler;
fail_handler m_fail_handler;
ping_handler m_ping_handler;
pong_handler m_pong_handler;
pong_timeout_handler m_pong_timeout_handler;
interrupt_handler m_interrupt_handler;
http_handler m_http_handler;
validate_handler m_validate_handler;
message_handler m_message_handler;
long m_open_handshake_timeout_dur;
long m_close_handshake_timeout_dur;
long m_pong_timeout_dur;
size_t m_max_message_size;
size_t m_max_http_body_size;
rng_type m_rng;
// static settings
bool const m_is_server;
// endpoint state
mutable mutex_type m_mutex;
};
} // namespace websocketpp
#include <websocketpp/impl/endpoint_impl.hpp>
#endif // WEBSOCKETPP_ENDPOINT_HPP

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_BASE_HPP
#define WEBSOCKETPP_ENDPOINT_BASE_HPP
namespace websocketpp {
/// Stub for user supplied base class.
class endpoint_base {};
} // namespace websocketpp
#endif // WEBSOCKETPP_ENDPOINT_BASE_HPP

View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 2014, 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_ERROR_HPP
#define WEBSOCKETPP_ERROR_HPP
#include <exception>
#include <string>
#include <utility>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
namespace websocketpp {
/// Combination error code / string type for returning two values
typedef std::pair<lib::error_code,std::string> err_str_pair;
/// Library level error codes
namespace error {
enum value {
/// Catch-all library error
general = 1,
/// send attempted when endpoint write queue was full
send_queue_full,
/// Attempted an operation using a payload that was improperly formatted
/// ex: invalid UTF8 encoding on a text message.
payload_violation,
/// Attempted to open a secure connection with an insecure endpoint
endpoint_not_secure,
/// Attempted an operation that required an endpoint that is no longer
/// available. This is usually because the endpoint went out of scope
/// before a connection that it created.
endpoint_unavailable,
/// An invalid uri was supplied
invalid_uri,
/// The endpoint is out of outgoing message buffers
no_outgoing_buffers,
/// The endpoint is out of incoming message buffers
no_incoming_buffers,
/// The connection was in the wrong state for this operation
invalid_state,
/// Unable to parse close code
bad_close_code,
/// Close code is in a reserved range
reserved_close_code,
/// Close code is invalid
invalid_close_code,
/// Invalid UTF-8
invalid_utf8,
/// Invalid subprotocol
invalid_subprotocol,
/// An operation was attempted on a connection that did not exist or was
/// already deleted.
bad_connection,
/// Unit testing utility error code
test,
/// Connection creation attempted failed
con_creation_failed,
/// Selected subprotocol was not requested by the client
unrequested_subprotocol,
/// Attempted to use a client specific feature on a server endpoint
client_only,
/// Attempted to use a server specific feature on a client endpoint
server_only,
/// HTTP connection ended
http_connection_ended,
/// WebSocket opening handshake timed out
open_handshake_timeout,
/// WebSocket close handshake timed out
close_handshake_timeout,
/// Invalid port in URI
invalid_port,
/// An async accept operation failed because the underlying transport has been
/// requested to not listen for new connections anymore.
async_accept_not_listening,
/// The requested operation was canceled
operation_canceled,
/// Connection rejected
rejected,
/// Upgrade Required. This happens if an HTTP request is made to a
/// WebSocket++ server that doesn't implement an http handler
upgrade_required,
/// Invalid WebSocket protocol version
invalid_version,
/// Unsupported WebSocket protocol version
unsupported_version,
/// HTTP parse error
http_parse_error,
/// Extension negotiation failed
extension_neg_failed
}; // enum value
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic error";
case error::send_queue_full:
return "send queue full";
case error::payload_violation:
return "payload violation";
case error::endpoint_not_secure:
return "endpoint not secure";
case error::endpoint_unavailable:
return "endpoint not available";
case error::invalid_uri:
return "invalid uri";
case error::no_outgoing_buffers:
return "no outgoing message buffers";
case error::no_incoming_buffers:
return "no incoming message buffers";
case error::invalid_state:
return "invalid state";
case error::bad_close_code:
return "Unable to extract close code";
case error::invalid_close_code:
return "Extracted close code is in an invalid range";
case error::reserved_close_code:
return "Extracted close code is in a reserved range";
case error::invalid_utf8:
return "Invalid UTF-8";
case error::invalid_subprotocol:
return "Invalid subprotocol";
case error::bad_connection:
return "Bad Connection";
case error::test:
return "Test Error";
case error::con_creation_failed:
return "Connection creation attempt failed";
case error::unrequested_subprotocol:
return "Selected subprotocol was not requested by the client";
case error::client_only:
return "Feature not available on server endpoints";
case error::server_only:
return "Feature not available on client endpoints";
case error::http_connection_ended:
return "HTTP connection ended";
case error::open_handshake_timeout:
return "The opening handshake timed out";
case error::close_handshake_timeout:
return "The closing handshake timed out";
case error::invalid_port:
return "Invalid URI port";
case error::async_accept_not_listening:
return "Async Accept not listening";
case error::operation_canceled:
return "Operation canceled";
case error::rejected:
return "Connection rejected";
case error::upgrade_required:
return "Upgrade required";
case error::invalid_version:
return "Invalid version";
case error::unsupported_version:
return "Unsupported version";
case error::http_parse_error:
return "HTTP parse error";
case error::extension_neg_failed:
return "Extension negotiation failed";
default:
return "Unknown";
}
}
};
inline const lib::error_category& get_category() {
static category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
namespace websocketpp {
class exception : public std::exception {
public:
exception(std::string const & msg, lib::error_code ec = make_error_code(error::general))
: m_msg(msg.empty() ? ec.message() : msg), m_code(ec)
{}
explicit exception(lib::error_code ec)
: m_msg(ec.message()), m_code(ec)
{}
~exception() throw() {}
virtual char const * what() const throw() {
return m_msg.c_str();
}
lib::error_code code() const throw() {
return m_code;
}
const std::string m_msg;
lib::error_code m_code;
};
} // namespace websocketpp
#endif // WEBSOCKETPP_ERROR_HPP

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2014, 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_EXTENSION_HPP
#define WEBSOCKETPP_EXTENSION_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
#include <vector>
namespace websocketpp {
/**
* Some generic information about extensions
*
* Each extension object has an implemented flag. It can be retrieved by calling
* is_implemented(). This compile time flag indicates whether or not the object
* in question actually implements the extension or if it is a placeholder stub
*
* Each extension object also has an enabled flag. It can be retrieved by
* calling is_enabled(). This runtime flag indicates whether or not the
* extension has been negotiated for this connection.
*/
namespace extensions {
namespace error {
enum value {
/// Catch all
general = 1,
/// Extension disabled
disabled
};
class category : public lib::error_category {
public:
category() {}
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.extension";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic extension error";
case disabled:
return "Use of methods from disabled extension";
default:
return "Unknown permessage-compress error";
}
}
};
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace extensions
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum
<websocketpp::extensions::error::value>
{
static const bool value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_EXTENSION_HPP

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2014, 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_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP
#define WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/http/constants.hpp>
#include <websocketpp/extensions/extension.hpp>
#include <map>
#include <string>
#include <utility>
namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Stub class for use when disabling permessage_deflate extension
/**
* This class is a stub that implements the permessage_deflate interface
* with minimal dependencies. It is used to disable permessage_deflate
* functionality at compile time without loading any unnecessary code.
*/
template <typename config>
class disabled {
typedef std::pair<lib::error_code,std::string> err_str_pair;
public:
/// Negotiate extension
/**
* The disabled extension always fails the negotiation with a disabled
* error.
*
* @param offer Attribute from client's offer
* @return Status code and value to return to remote endpoint
*/
err_str_pair negotiate(http::attribute_list const &) {
return make_pair(make_error_code(error::disabled),std::string());
}
/// Initialize state
/**
* For the disabled extension state initialization is a no-op.
*
* @param is_server True to initialize as a server, false for a client.
* @return A code representing the error that occurred, if any
*/
lib::error_code init(bool) {
return lib::error_code();
}
/// Returns true if the extension is capable of providing
/// permessage_deflate functionality
bool is_implemented() const {
return false;
}
/// Returns true if permessage_deflate functionality is active for this
/// connection
bool is_enabled() const {
return false;
}
/// Generate extension offer
/**
* Creates an offer string to include in the Sec-WebSocket-Extensions
* header of outgoing client requests.
*
* @return A WebSocket extension offer string for this extension
*/
std::string generate_offer() const {
return "";
}
/// Compress bytes
/**
* @param [in] in String to compress
* @param [out] out String to append compressed bytes to
* @return Error or status code
*/
lib::error_code compress(std::string const &, std::string &) {
return make_error_code(error::disabled);
}
/// Decompress bytes
/**
* @param buf Byte buffer to decompress
* @param len Length of buf
* @param out String to append decompressed bytes to
* @return Error or status code
*/
lib::error_code decompress(uint8_t const *, size_t, std::string &) {
return make_error_code(error::disabled);
}
};
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
#endif // WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP

View File

@@ -0,0 +1,817 @@
/*
* Copyright (c) 2015, 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_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/error.hpp>
#include <websocketpp/extensions/extension.hpp>
#include "zlib.h"
#include <algorithm>
#include <string>
#include <vector>
namespace websocketpp {
namespace extensions {
/// Implementation of RFC 7692, the permessage-deflate WebSocket extension
/**
* ### permessage-deflate interface
*
* **init**\n
* `lib::error_code init(bool is_server)`\n
* Performs initialization
*
* **is_implimented**\n
* `bool is_implimented()`\n
* Returns whether or not the object impliments the extension or not
*
* **is_enabled**\n
* `bool is_enabled()`\n
* Returns whether or not the extension was negotiated for the current
* connection
*
* **generate_offer**\n
* `std::string generate_offer() const`\n
* Create an extension offer string based on local policy
*
* **validate_response**\n
* `lib::error_code validate_response(http::attribute_list const & response)`\n
* Negotiate the parameters of extension use
*
* **negotiate**\n
* `err_str_pair negotiate(http::attribute_list const & attributes)`\n
* Negotiate the parameters of extension use
*
* **compress**\n
* `lib::error_code compress(std::string const & in, std::string & out)`\n
* Compress the bytes in `in` and append them to `out`
*
* **decompress**\n
* `lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
* out)`\n
* Decompress `len` bytes from `buf` and append them to string `out`
*/
namespace permessage_deflate {
/// Permessage deflate error values
namespace error {
enum value {
/// Catch all
general = 1,
/// Invalid extension attributes
invalid_attributes,
/// Invalid extension attribute value
invalid_attribute_value,
/// Invalid megotiation mode
invalid_mode,
/// Unsupported extension attributes
unsupported_attributes,
/// Invalid value for max_window_bits
invalid_max_window_bits,
/// ZLib Error
zlib_error,
/// Uninitialized
uninitialized,
};
/// Permessage-deflate error category
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.extension.permessage-deflate";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic permessage-compress error";
case invalid_attributes:
return "Invalid extension attributes";
case invalid_attribute_value:
return "Invalid extension attribute value";
case invalid_mode:
return "Invalid permessage-deflate negotiation mode";
case unsupported_attributes:
return "Unsupported extension attributes";
case invalid_max_window_bits:
return "Invalid value for max_window_bits";
case zlib_error:
return "A zlib function returned an error";
case uninitialized:
return "Deflate extension must be initialized before use";
default:
return "Unknown permessage-compress error";
}
}
};
/// Get a reference to a static copy of the permessage-deflate error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Create an error code in the permessage-deflate category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum
<websocketpp::extensions::permessage_deflate::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Default value for server_max_window_bits as defined by RFC 7692
static uint8_t const default_server_max_window_bits = 15;
/// Minimum value for server_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_server_max_window_bits = 8;
/// Maximum value for server_max_window_bits as defined by RFC 7692
static uint8_t const max_server_max_window_bits = 15;
/// Default value for client_max_window_bits as defined by RFC 7692
static uint8_t const default_client_max_window_bits = 15;
/// Minimum value for client_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_client_max_window_bits = 8;
/// Maximum value for client_max_window_bits as defined by RFC 7692
static uint8_t const max_client_max_window_bits = 15;
namespace mode {
enum value {
/// Accept any value the remote endpoint offers
accept = 1,
/// Decline any value the remote endpoint offers. Insist on defaults.
decline,
/// Use the largest value common to both offers
largest,
/// Use the smallest value common to both offers
smallest
};
} // namespace mode
template <typename config>
class enabled {
public:
enabled()
: m_enabled(false)
, m_server_no_context_takeover(false)
, m_client_no_context_takeover(false)
, m_server_max_window_bits(15)
, m_client_max_window_bits(15)
, m_server_max_window_bits_mode(mode::accept)
, m_client_max_window_bits_mode(mode::accept)
, m_initialized(false)
, m_compress_buffer_size(8192)
{
m_dstate.zalloc = Z_NULL;
m_dstate.zfree = Z_NULL;
m_dstate.opaque = Z_NULL;
m_istate.zalloc = Z_NULL;
m_istate.zfree = Z_NULL;
m_istate.opaque = Z_NULL;
m_istate.avail_in = 0;
m_istate.next_in = Z_NULL;
}
~enabled() {
if (!m_initialized) {
return;
}
int ret = deflateEnd(&m_dstate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib compression state"
// << std::endl;
}
ret = inflateEnd(&m_istate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib decompression state"
// << std::endl;
}
}
/// Initialize zlib state
/**
* Note: this should be called *after* the negotiation methods. It will use
* information from the negotiation to determine how to initialize the zlib
* data structures.
*
* @todo memory level, strategy, etc are hardcoded
*
* @param is_server True to initialize as a server, false for a client.
* @return A code representing the error that occurred, if any
*/
lib::error_code init(bool is_server) {
uint8_t deflate_bits;
uint8_t inflate_bits;
if (is_server) {
deflate_bits = m_server_max_window_bits;
inflate_bits = m_client_max_window_bits;
} else {
deflate_bits = m_client_max_window_bits;
inflate_bits = m_server_max_window_bits;
}
int ret = deflateInit2(
&m_dstate,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
-1*deflate_bits,
4, // memory level 1-9
Z_DEFAULT_STRATEGY
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
ret = inflateInit2(
&m_istate,
-1*inflate_bits
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]);
if ((m_server_no_context_takeover && is_server) ||
(m_client_no_context_takeover && !is_server))
{
m_flush = Z_FULL_FLUSH;
} else {
m_flush = Z_SYNC_FLUSH;
}
m_initialized = true;
return lib::error_code();
}
/// Test if this object implements the permessage-deflate specification
/**
* Because this object does implieent it, it will always return true.
*
* @return Whether or not this object implements permessage-deflate
*/
bool is_implemented() const {
return true;
}
/// Test if the extension was negotiated for this connection
/**
* Retrieves whether or not this extension is in use based on the initial
* handshake extension negotiations.
*
* @return Whether or not the extension is in use
*/
bool is_enabled() const {
return m_enabled;
}
/// Reset server's outgoing LZ77 sliding window for each new message
/**
* Enabling this setting will cause the server's compressor to reset the
* compression state (the LZ77 sliding window) for every message. This
* means that the compressor will not look back to patterns in previous
* messages to improve compression. This will reduce the compression
* efficiency for large messages somewhat and small messages drastically.
*
* This option may reduce server compressor memory usage and client
* decompressor memory usage.
* @todo Document to what extent memory usage will be reduced
*
* For clients, this option is dependent on server support. Enabling it
* via this method does not guarantee that it will be successfully
* negotiated, only that it will be requested.
*
* For servers, no client support is required. Enabling this option on a
* server will result in its use. The server will signal to clients that
* the option will be in use so they can optimize resource usage if they
* are able.
*/
void enable_server_no_context_takeover() {
m_server_no_context_takeover = true;
}
/// Reset client's outgoing LZ77 sliding window for each new message
/**
* Enabling this setting will cause the client's compressor to reset the
* compression state (the LZ77 sliding window) for every message. This
* means that the compressor will not look back to patterns in previous
* messages to improve compression. This will reduce the compression
* efficiency for large messages somewhat and small messages drastically.
*
* This option may reduce client compressor memory usage and server
* decompressor memory usage.
* @todo Document to what extent memory usage will be reduced
*
* This option is supported by all compliant clients and servers. Enabling
* it via either endpoint should be sufficient to ensure it is used.
*/
void enable_client_no_context_takeover() {
m_client_no_context_takeover = true;
}
/// Limit server LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the maximum window size that
* the server must use to compress outgoing messages. The permitted range
* is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB
* window. The default setting is 15.
*
* Mode Options:
* - accept: Accept whatever the remote endpoint offers.
* - decline: Decline any offers to deviate from the defaults
* - largest: Accept largest window size acceptable to both endpoints
* - smallest: Accept smallest window size acceptiable to both endpoints
*
* This setting is dependent on server support. A client requesting this
* setting may be rejected by the server or have the exact value used
* adjusted by the server. A server may unilaterally set this value without
* client support.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
*/
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_server_max_window_bits = bits;
m_server_max_window_bits_mode = mode;
return lib::error_code();
}
/// Limit client LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the window size that the
* client must use to compress outgoing messages. The permitted range is 9
* to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.
* The default setting is 15.
*
* Mode Options:
* - accept: Accept whatever the remote endpoint offers.
* - decline: Decline any offers to deviate from the defaults
* - largest: Accept largest window size acceptable to both endpoints
* - smallest: Accept smallest window size acceptiable to both endpoints
*
* This setting is dependent on client support. A client may limit its own
* outgoing window size unilaterally. A server may only limit the client's
* window size if the remote client supports that feature.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
*/
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_client_max_window_bits = bits;
m_client_max_window_bits_mode = mode;
return lib::error_code();
}
/// Generate extension offer
/**
* Creates an offer string to include in the Sec-WebSocket-Extensions
* header of outgoing client requests.
*
* @return A WebSocket extension offer string for this extension
*/
std::string generate_offer() const {
// TODO: this should be dynamically generated based on user settings
return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
}
/// Validate extension response
/**
* Confirm that the server has negotiated settings compatible with our
* original offer and apply those settings to the extension state.
*
* @param response The server response attribute list to validate
* @return Validation error or 0 on success
*/
lib::error_code validate_offer(http::attribute_list const &) {
return lib::error_code();
}
/// Negotiate extension
/**
* Confirm that the client's extension negotiation offer has settings
* compatible with local policy. If so, generate a reply and apply those
* settings to the extension state.
*
* @param offer Attribute from client's offer
* @return Status code and value to return to remote endpoint
*/
err_str_pair negotiate(http::attribute_list const & offer) {
err_str_pair ret;
http::attribute_list::const_iterator it;
for (it = offer.begin(); it != offer.end(); ++it) {
if (it->first == "server_no_context_takeover") {
negotiate_server_no_context_takeover(it->second,ret.first);
} else if (it->first == "client_no_context_takeover") {
negotiate_client_no_context_takeover(it->second,ret.first);
} else if (it->first == "server_max_window_bits") {
negotiate_server_max_window_bits(it->second,ret.first);
} else if (it->first == "client_max_window_bits") {
negotiate_client_max_window_bits(it->second,ret.first);
} else {
ret.first = make_error_code(error::invalid_attributes);
}
if (ret.first) {
break;
}
}
if (ret.first == lib::error_code()) {
m_enabled = true;
ret.second = generate_response();
}
return ret;
}
/// Compress bytes
/**
* @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames
* on 64 bit machines.
*
* @param [in] in String to compress
* @param [out] out String to append compressed bytes to
* @return Error or status code
*/
lib::error_code compress(std::string const & in, std::string & out) {
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
size_t output;
if (in.empty()) {
uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
out.append((char *)(buf),6);
return lib::error_code();
}
m_dstate.avail_in = in.size();
m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
do {
// Output to local buffer
m_dstate.avail_out = m_compress_buffer_size;
m_dstate.next_out = m_compress_buffer.get();
deflate(&m_dstate, m_flush);
output = m_compress_buffer_size - m_dstate.avail_out;
out.append((char *)(m_compress_buffer.get()),output);
} while (m_dstate.avail_out == 0);
return lib::error_code();
}
/// Decompress bytes
/**
* @param buf Byte buffer to decompress
* @param len Length of buf
* @param out String to append decompressed bytes to
* @return Error or status code
*/
lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
out)
{
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
int ret;
m_istate.avail_in = len;
m_istate.next_in = const_cast<unsigned char *>(buf);
do {
m_istate.avail_out = m_compress_buffer_size;
m_istate.next_out = m_decompress_buffer.get();
ret = inflate(&m_istate, Z_SYNC_FLUSH);
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
return make_error_code(error::zlib_error);
}
out.append(
reinterpret_cast<char *>(m_decompress_buffer.get()),
m_compress_buffer_size - m_istate.avail_out
);
} while (m_istate.avail_out == 0);
return lib::error_code();
}
private:
/// Generate negotiation response
/**
* @return Generate extension negotiation reponse string to send to client
*/
std::string generate_response() {
std::string ret = "permessage-deflate";
if (m_server_no_context_takeover) {
ret += "; server_no_context_takeover";
}
if (m_client_no_context_takeover) {
ret += "; client_no_context_takeover";
}
if (m_server_max_window_bits < default_server_max_window_bits) {
std::stringstream s;
s << int(m_server_max_window_bits);
ret += "; server_max_window_bits="+s.str();
}
if (m_client_max_window_bits < default_client_max_window_bits) {
std::stringstream s;
s << int(m_client_max_window_bits);
ret += "; client_max_window_bits="+s.str();
}
return ret;
}
/// Negotiate server_no_context_takeover attribute
/**
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_server_no_context_takeover(std::string const & value,
lib::error_code & ec)
{
if (!value.empty()) {
ec = make_error_code(error::invalid_attribute_value);
return;
}
m_server_no_context_takeover = true;
}
/// Negotiate client_no_context_takeover attribute
/**
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_client_no_context_takeover(std::string const & value,
lib::error_code & ec)
{
if (!value.empty()) {
ec = make_error_code(error::invalid_attribute_value);
return;
}
m_client_no_context_takeover = true;
}
/// Negotiate server_max_window_bits attribute
/**
* When this method starts, m_server_max_window_bits will contain the server's
* preferred value and m_server_max_window_bits_mode will contain the mode the
* server wants to use to for negotiation. `value` contains the value the
* client requested that we use.
*
* options:
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_server_max_window_bits(std::string const & value,
lib::error_code & ec)
{
uint8_t bits = uint8_t(atoi(value.c_str()));
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
ec = make_error_code(error::invalid_attribute_value);
m_server_max_window_bits = default_server_max_window_bits;
return;
}
switch (m_server_max_window_bits_mode) {
case mode::decline:
m_server_max_window_bits = default_server_max_window_bits;
break;
case mode::accept:
m_server_max_window_bits = bits;
break;
case mode::largest:
m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
break;
case mode::smallest:
m_server_max_window_bits = min_server_max_window_bits;
break;
default:
ec = make_error_code(error::invalid_mode);
m_server_max_window_bits = default_server_max_window_bits;
}
// See note in doc comment
if (m_server_max_window_bits == 8) {
m_server_max_window_bits = 9;
}
}
/// Negotiate client_max_window_bits attribute
/**
* When this method starts, m_client_max_window_bits and m_c2s_max_window_mode
* will contain the server's preferred values for window size and
* negotiation mode.
*
* options:
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_client_max_window_bits(std::string const & value,
lib::error_code & ec)
{
uint8_t bits = uint8_t(atoi(value.c_str()));
if (value.empty()) {
bits = default_client_max_window_bits;
} else if (bits < min_client_max_window_bits ||
bits > max_client_max_window_bits)
{
ec = make_error_code(error::invalid_attribute_value);
m_client_max_window_bits = default_client_max_window_bits;
return;
}
switch (m_client_max_window_bits_mode) {
case mode::decline:
m_client_max_window_bits = default_client_max_window_bits;
break;
case mode::accept:
m_client_max_window_bits = bits;
break;
case mode::largest:
m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
break;
case mode::smallest:
m_client_max_window_bits = min_client_max_window_bits;
break;
default:
ec = make_error_code(error::invalid_mode);
m_client_max_window_bits = default_client_max_window_bits;
}
// See note in doc comment
if (m_client_max_window_bits == 8) {
m_client_max_window_bits = 9;
}
}
bool m_enabled;
bool m_server_no_context_takeover;
bool m_client_no_context_takeover;
uint8_t m_server_max_window_bits;
uint8_t m_client_max_window_bits;
mode::value m_server_max_window_bits_mode;
mode::value m_client_max_window_bits_mode;
bool m_initialized;
int m_flush;
size_t m_compress_buffer_size;
lib::unique_ptr_uchar_array m_compress_buffer;
lib::unique_ptr_uchar_array m_decompress_buffer;
z_stream m_dstate;
z_stream m_istate;
};
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
#endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP

View File

@@ -0,0 +1,864 @@
/*
* Copyright (c) 2014, 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_FRAME_HPP
#define WEBSOCKETPP_FRAME_HPP
#include <algorithm>
#include <string>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/utilities.hpp>
namespace websocketpp {
/// Data structures and utility functions for manipulating WebSocket frames
/**
* namespace frame provides a number of data structures and utility functions
* for reading, writing, and manipulating binary encoded WebSocket frames.
*/
namespace frame {
/// Minimum length of a WebSocket frame header.
static unsigned int const BASIC_HEADER_LENGTH = 2;
/// Maximum length of a WebSocket header
static unsigned int const MAX_HEADER_LENGTH = 14;
/// Maximum length of the variable portion of the WebSocket header
static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;
/// Two byte conversion union
union uint16_converter {
uint16_t i;
uint8_t c[2];
};
/// Four byte conversion union
union uint32_converter {
uint32_t i;
uint8_t c[4];
};
/// Eight byte conversion union
union uint64_converter {
uint64_t i;
uint8_t c[8];
};
/// Constants and utility functions related to WebSocket opcodes
/**
* WebSocket Opcodes are 4 bits. See RFC6455 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,
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
};
/// Check if an opcode is reserved
/**
* @param v The opcode to test.
* @return Whether or not the opcode is reserved.
*/
inline bool reserved(value v) {
return (v >= rsv3 && v <= rsv7) ||
(v >= control_rsvb && v <= control_rsvf);
}
/// Check if an opcode is invalid
/**
* Invalid opcodes are negative or require greater than 4 bits to store.
*
* @param v The opcode to test.
* @return Whether or not the opcode is invalid.
*/
inline bool invalid(value v) {
return (v > 0xF || v < 0);
}
/// Check if an opcode is for a control frame
/**
* @param v The opcode to test.
* @return Whether or not the opcode is a control opcode.
*/
inline bool is_control(value v) {
return v >= 0x8;
}
}
/// Constants related to frame and payload limits
namespace limits {
/// Minimum length of a WebSocket frame header.
static unsigned int const basic_header_length = 2;
/// Maximum length of a WebSocket header
static unsigned int const max_header_length = 14;
/// Maximum length of the variable portion of the WebSocket header
static unsigned int const max_extended_header_length = 12;
/// Maximum size of a basic WebSocket payload
static uint8_t const payload_size_basic = 125;
/// Maximum size of an extended WebSocket payload (basic payload = 126)
static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535
/// Maximum size of a jumbo WebSocket payload (basic payload = 127)
static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63
/// Maximum size of close frame reason
/**
* This is payload_size_basic - 2 bytes (as first two bytes are used for
* the close code
*/
static uint8_t const close_reason_size = 123;
}
// masks for fields in the basic header
static uint8_t const BHB0_OPCODE = 0x0F;
static uint8_t const BHB0_RSV3 = 0x10;
static uint8_t const BHB0_RSV2 = 0x20;
static uint8_t const BHB0_RSV1 = 0x40;
static uint8_t const BHB0_FIN = 0x80;
static uint8_t const BHB1_PAYLOAD = 0x7F;
static uint8_t const BHB1_MASK = 0x80;
static uint8_t const payload_size_code_16bit = 0x7E; // 126
static uint8_t const payload_size_code_64bit = 0x7F; // 127
typedef uint32_converter masking_key_type;
/// The constant size component of a WebSocket frame header
struct basic_header {
basic_header() : b0(0x00),b1(0x00) {}
basic_header(uint8_t p0, uint8_t p1) : b0(p0), b1(p1) {}
basic_header(opcode::value op, uint64_t size, bool fin, bool mask,
bool rsv1 = false, bool rsv2 = false, bool rsv3 = false) : b0(0x00),
b1(0x00)
{
if (fin) {
b0 |= BHB0_FIN;
}
if (rsv1) {
b0 |= BHB0_RSV1;
}
if (rsv2) {
b0 |= BHB0_RSV2;
}
if (rsv3) {
b0 |= BHB0_RSV3;
}
b0 |= (op & BHB0_OPCODE);
if (mask) {
b1 |= BHB1_MASK;
}
uint8_t basic_value;
if (size <= limits::payload_size_basic) {
basic_value = static_cast<uint8_t>(size);
} else if (size <= limits::payload_size_extended) {
basic_value = payload_size_code_16bit;
} else {
basic_value = payload_size_code_64bit;
}
b1 |= basic_value;
}
uint8_t b0;
uint8_t b1;
};
/// The variable size component of a WebSocket frame header
struct extended_header {
extended_header() {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
}
extended_header(uint64_t payload_size) {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
copy_payload(payload_size);
}
extended_header(uint64_t payload_size, uint32_t masking_key) {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
// Copy payload size
int offset = copy_payload(payload_size);
// Copy Masking Key
uint32_converter temp32;
temp32.i = masking_key;
std::copy(temp32.c,temp32.c+4,bytes+offset);
}
uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH];
private:
int copy_payload(uint64_t payload_size) {
int payload_offset = 0;
if (payload_size <= limits::payload_size_basic) {
payload_offset = 8;
} else if (payload_size <= limits::payload_size_extended) {
payload_offset = 6;
}
uint64_converter temp64;
temp64.i = lib::net::_htonll(payload_size);
std::copy(temp64.c+payload_offset,temp64.c+8,bytes);
return 8-payload_offset;
}
};
bool get_fin(basic_header const &h);
void set_fin(basic_header &h, bool value);
bool get_rsv1(basic_header const &h);
void set_rsv1(basic_header &h, bool value);
bool get_rsv2(basic_header const &h);
void set_rsv2(basic_header &h, bool value);
bool get_rsv3(basic_header const &h);
void set_rsv3(basic_header &h, bool value);
opcode::value get_opcode(basic_header const &h);
bool get_masked(basic_header const &h);
void set_masked(basic_header &h, bool value);
uint8_t get_basic_size(basic_header const &);
size_t get_header_len(basic_header const &);
unsigned int get_masking_key_offset(basic_header const &);
std::string write_header(basic_header const &, extended_header const &);
masking_key_type get_masking_key(basic_header const &, extended_header const &);
uint16_t get_extended_size(extended_header const &);
uint64_t get_jumbo_size(extended_header const &);
uint64_t get_payload_size(basic_header const &, extended_header const &);
size_t prepare_masking_key(masking_key_type const & key);
size_t circshift_prepared_key(size_t prepared_key, size_t offset);
// Functions for performing xor based masking and unmasking
template <typename input_iter, typename output_iter>
void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
const & key, size_t key_offset = 0);
template <typename iter_type>
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
size_t key_offset = 0);
void word_mask_exact(uint8_t * input, uint8_t * output, size_t length,
masking_key_type const & key);
void word_mask_exact(uint8_t * data, size_t length, masking_key_type const &
key);
size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key);
size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);
/// Check whether the frame's FIN bit is set.
/**
* @param [in] h The basic header to extract from.
* @return True if the header's fin bit is set.
*/
inline bool get_fin(basic_header const & h) {
return ((h.b0 & BHB0_FIN) == BHB0_FIN);
}
/// Set the frame's FIN bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_fin(basic_header & h, bool value) {
h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
}
/// check whether the frame's RSV1 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV1 bit is set.
*/
inline bool get_rsv1(const basic_header &h) {
return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
}
/// Set the frame's RSV1 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv1(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
}
/// check whether the frame's RSV2 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV2 bit is set.
*/
inline bool get_rsv2(const basic_header &h) {
return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
}
/// Set the frame's RSV2 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv2(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
}
/// check whether the frame's RSV3 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV3 bit is set.
*/
inline bool get_rsv3(const basic_header &h) {
return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
}
/// Set the frame's RSV3 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv3(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
}
/// Extract opcode from basic header
/**
* @param [in] h The basic header to extract from.
* @return The opcode value of the header.
*/
inline opcode::value get_opcode(const basic_header &h) {
return opcode::value(h.b0 & BHB0_OPCODE);
}
/// check whether the frame is masked
/**
* @param [in] h The basic header to extract from.
* @return True if the header mask bit is set.
*/
inline bool get_masked(basic_header const & h) {
return ((h.b1 & BHB1_MASK) == BHB1_MASK);
}
/// Set the frame's MASK bit
/**
* @param [out] h Header to set.
* @param value Value to set it to.
*/
inline void set_masked(basic_header & h, bool value) {
h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
}
/// Extracts the raw payload length specified in the basic header
/**
* A basic WebSocket frame header contains a 7 bit value that represents the
* payload size. There are two reserved values that are used to indicate that
* the actual payload size will not fit in 7 bits and that the full payload
* size is included in a separate field. The values are as follows:
*
* PAYLOAD_SIZE_CODE_16BIT (0x7E) indicates that the actual payload is less
* than 16 bit
*
* PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less
* than 63 bit
*
* @param [in] h Basic header to read value from.
* @return The exact size encoded in h.
*/
inline uint8_t get_basic_size(const basic_header &h) {
return h.b1 & BHB1_PAYLOAD;
}
/// Calculates the full length of the header based on the first bytes.
/**
* A WebSocket frame header always has at least two bytes. Encoded within the
* first two bytes is all the information necessary to calculate the full
* (variable) header length. get_header_len() calculates the full header
* length for the given two byte basic header.
*
* @param h Basic frame header to extract size from.
* @return Full length of the extended header.
*/
inline size_t get_header_len(basic_header const & h) {
// TODO: check extensions?
// masking key offset represents the space used for the extended length
// fields
size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h);
// If the header is masked there is a 4 byte masking key
if (get_masked(h)) {
size += 4;
}
return size;
}
/// Calculate the offset location of the masking key within the extended header
/**
* Calculate the offset location of the masking key within the extended header
* using information from its corresponding basic header
*
* @param h Corresponding basic header to calculate from.
*
* @return byte offset of the first byte of the masking key
*/
inline unsigned int get_masking_key_offset(const basic_header &h) {
if (get_basic_size(h) == payload_size_code_16bit) {
return 2;
} else if (get_basic_size(h) == payload_size_code_64bit) {
return 8;
} else {
return 0;
}
}
/// Generate a properly sized contiguous string that encodes a full frame header
/**
* Copy the basic header h and extended header e into a properly sized
* contiguous frame header string for the purposes of writing out to the wire.
*
* @param h The basic header to include
* @param e The extended header to include
*
* @return A contiguous string containing h and e
*/
inline std::string prepare_header(const basic_header &h, const
extended_header &e)
{
std::string ret;
ret.push_back(char(h.b0));
ret.push_back(char(h.b1));
ret.append(
reinterpret_cast<const char*>(e.bytes),
get_header_len(h)-BASIC_HEADER_LENGTH
);
return ret;
}
/// Extract the masking key from a frame header
/**
* Note that while read and written as an integer at times, this value is not
* an integer and should never be interpreted as one. Big and little endian
* machines will generate and store masking keys differently without issue as
* long as the integer values remain irrelivant.
*
* @param h The basic header to extract from
* @param e The extended header to extract from
*
* @return The masking key as an integer.
*/
inline masking_key_type get_masking_key(const basic_header &h, const
extended_header &e)
{
masking_key_type temp32;
if (!get_masked(h)) {
temp32.i = 0;
} else {
unsigned int offset = get_masking_key_offset(h);
std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c);
}
return temp32;
}
/// Extract the extended size field from an extended header
/**
* It is the responsibility of the caller to verify that e is a valid extended
* header. This function assumes that e contains an extended payload size.
*
* @param e The extended header to extract from
*
* @return The size encoded in the extended header in host byte order
*/
inline uint16_t get_extended_size(const extended_header &e) {
uint16_converter temp16;
std::copy(e.bytes,e.bytes+2,temp16.c);
return ntohs(temp16.i);
}
/// Extract the jumbo size field from an extended header
/**
* It is the responsibility of the caller to verify that e is a valid extended
* header. This function assumes that e contains a jumbo payload size.
*
* @param e The extended header to extract from
*
* @return The size encoded in the extended header in host byte order
*/
inline uint64_t get_jumbo_size(const extended_header &e) {
uint64_converter temp64;
std::copy(e.bytes,e.bytes+8,temp64.c);
return lib::net::_ntohll(temp64.i);
}
/// Extract the full payload size field from a WebSocket header
/**
* It is the responsibility of the caller to verify that h and e together
* represent a valid WebSocket frame header. This function assumes only that h
* and e are valid. It uses information in the basic header to determine where
* to look for the payload_size
*
* @param h The basic header to extract from
* @param e The extended header to extract from
*
* @return The size encoded in the combined header in host byte order.
*/
inline uint64_t get_payload_size(const basic_header &h, const
extended_header &e)
{
uint8_t val = get_basic_size(h);
if (val <= limits::payload_size_basic) {
return val;
} else if (val == payload_size_code_16bit) {
return get_extended_size(e);
} else {
return get_jumbo_size(e);
}
}
/// Extract a masking key into a value the size of a machine word.
/**
* Machine word size must be 4 or 8.
*
* @param key Masking key to extract from
*
* @return prepared key as a machine word
*/
inline size_t prepare_masking_key(const masking_key_type& key) {
size_t low_bits = static_cast<size_t>(key.i);
if (sizeof(size_t) == 8) {
uint64_t high_bits = static_cast<size_t>(key.i);
return static_cast<size_t>((high_bits << 32) | low_bits);
} else {
return low_bits;
}
}
/// circularly shifts the supplied prepared masking key by offset bytes
/**
* Prepared_key must be the output of prepare_masking_key with the associated
* restrictions on the machine word size. offset must be greater than or equal
* to zero and less than sizeof(size_t).
*/
inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
if (offset == 0) {
return prepared_key;
}
if (lib::net::is_little_endian()) {
size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
return (prepared_key >> offset*8) | temp;
} else {
size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;
return (prepared_key << offset*8) | temp;
}
}
/// Byte by byte mask/unmask
/**
* Iterator based byte by byte masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key offset by the supplied
* offset number of bytes.
*
* This function is simple and can be done in place on input with arbitrary
* lengths and does not vary based on machine word size. It is slow.
*
* @param b Beginning iterator to start masking
*
* @param e Ending iterator to end masking
*
* @param o Beginning iterator to store masked results
*
* @param key 32 bit key to mask with.
*
* @param key_offset offset value to start masking at.
*/
template <typename input_iter, typename output_iter>
void byte_mask(input_iter first, input_iter last, output_iter result,
masking_key_type const & key, size_t key_offset)
{
size_t key_index = key_offset%4;
while (first != last) {
*result = *first ^ key.c[key_index++];
key_index %= 4;
++result;
++first;
}
}
/// Byte by byte mask/unmask (in place)
/**
* Iterator based byte by byte masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key offset by the supplied
* offset number of bytes.
*
* This function is simple and can be done in place on input with arbitrary
* lengths and does not vary based on machine word size. It is slow.
*
* @param b Beginning iterator to start masking
*
* @param e Ending iterator to end masking
*
* @param key 32 bit key to mask with.
*
* @param key_offset offset value to start masking at.
*/
template <typename iter_type>
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
size_t key_offset)
{
byte_mask(b,e,b,key,key_offset);
}
/// Exact word aligned mask/unmask
/**
* Balanced combination of byte by byte and circular word by word masking.
* Best used to mask complete messages at once. Has much higher setup costs than
* word_mask_circ but works with exact sized buffers.
*
* Buffer based word by word masking and unmasking for WebSocket payloads.
* Masking is done in word by word chunks with the remainder not divisible by
* the word size done byte by byte.
*
* input and output must both be at least length bytes. Exactly length bytes
* will be written.
*
* @param input buffer to mask or unmask
*
* @param output buffer to store the output. May be the same as input.
*
* @param length length of data buffer
*
* @param key Masking key to use
*/
inline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,
const masking_key_type& key)
{
size_t prepared_key = prepare_masking_key(key);
size_t n = length/sizeof(size_t);
size_t* input_word = reinterpret_cast<size_t*>(input);
size_t* output_word = reinterpret_cast<size_t*>(output);
for (size_t i = 0; i < n; i++) {
output_word[i] = input_word[i] ^ prepared_key;
}
for (size_t i = n*sizeof(size_t); i < length; i++) {
output[i] = input[i] ^ key.c[i%4];
}
}
/// Exact word aligned mask/unmask (in place)
/**
* In place version of word_mask_exact
*
* @see word_mask_exact
*
* @param data buffer to read and write from
*
* @param length length of data buffer
*
* @param key Masking key to use
*/
inline void word_mask_exact(uint8_t* data, size_t length, const
masking_key_type& key)
{
word_mask_exact(data,data,length,key);
}
/// Circular word aligned mask/unmask
/**
* Performs a circular mask/unmask in word sized chunks using pre-prepared keys
* that store state between calls. Best for providing streaming masking or
* unmasking of small chunks at a time of a larger message. Requires that the
* underlying allocated size of the data buffer be a multiple of the word size.
* Data in the buffer after `length` will be overwritten only with the same
* values that were originally present.
*
* Buffer based word by word masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key. Casts the data buffer to
* an array of size_t's and performs masking word by word. The underlying
* buffer size must be a muliple of the word size.
*
* word_mask returns a copy of prepared_key circularly shifted based on the
* length value. The returned value may be fed back into word_mask when more
* data is available.
*
* input and output must both have length at least:
* ceil(length/sizeof(size_t))*sizeof(size_t)
* Exactly that many bytes will be written, although only exactly length bytes
* will be changed (trailing bytes will be replaced without masking)
*
* @param data Character buffer to mask
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key)
{
size_t n = length / sizeof(size_t); // whole words
size_t l = length - (n * sizeof(size_t)); // remaining bytes
size_t * input_word = reinterpret_cast<size_t *>(input);
size_t * output_word = reinterpret_cast<size_t *>(output);
// mask word by word
for (size_t i = 0; i < n; i++) {
output_word[i] = input_word[i] ^ prepared_key;
}
// mask partial word at the end
size_t start = length - l;
uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);
for (size_t i = 0; i < l; ++i) {
output[start+i] = input[start+i] ^ byte_key[i];
}
return circshift_prepared_key(prepared_key,l);
}
/// Circular word aligned mask/unmask (in place)
/**
* In place version of word_mask_circ
*
* @see word_mask_circ
*
* @param data Character buffer to read from and write to
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
return word_mask_circ(data,data,length,prepared_key);
}
/// Circular byte aligned mask/unmask
/**
* Performs a circular mask/unmask in byte sized chunks using pre-prepared keys
* that store state between calls. Best for providing streaming masking or
* unmasking of small chunks at a time of a larger message. Requires that the
* underlying allocated size of the data buffer be a multiple of the word size.
* Data in the buffer after `length` will be overwritten only with the same
* values that were originally present.
*
* word_mask returns a copy of prepared_key circularly shifted based on the
* length value. The returned value may be fed back into byte_mask when more
* data is available.
*
* @param data Character buffer to mask
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key)
{
uint32_converter key;
key.i = prepared_key;
for (size_t i = 0; i < length; ++i) {
output[i] = input[i] ^ key.c[i % 4];
}
return circshift_prepared_key(prepared_key,length % 4);
}
/// Circular byte aligned mask/unmask (in place)
/**
* In place version of byte_mask_circ
*
* @see byte_mask_circ
*
* @param data Character buffer to read from and write to
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
return byte_mask_circ(data,data,length,prepared_key);
}
} // namespace frame
} // namespace websocketpp
#endif //WEBSOCKETPP_FRAME_HPP

View File

@@ -0,0 +1,308 @@
/*
* Copyright (c) 2014, 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 HTTP_CONSTANTS_HPP
#define HTTP_CONSTANTS_HPP
#include <exception>
#include <map>
#include <string>
#include <vector>
#include <utility>
namespace websocketpp {
/// HTTP handling support
namespace http {
/// The type of an HTTP attribute list
/**
* The attribute list is an unordered key/value map. Encoded attribute
* values are delimited by semicolons.
*/
typedef std::map<std::string,std::string> attribute_list;
/// The type of an HTTP parameter list
/**
* The parameter list is an ordered pairing of a parameter and its
* associated attribute list. Encoded parameter values are delimited by
* commas.
*/
typedef std::vector< std::pair<std::string,attribute_list> > parameter_list;
/// Literal value of the HTTP header delimiter
static char const header_delimiter[] = "\r\n";
/// Literal value of the HTTP header separator
static char const header_separator[] = ":";
/// Literal value of an empty header
static std::string const empty_header;
/// Maximum size in bytes before rejecting an HTTP header as too big.
size_t const max_header_size = 16000;
/// Default Maximum size in bytes for HTTP message bodies.
size_t const max_body_size = 32000000;
/// Number of bytes to use for temporary istream read buffers
size_t const istream_buffer = 512;
/// invalid HTTP token characters
/**
* 0x00 - 0x32, 0x7f-0xff
* ( ) < > @ , ; : \ " / [ ] ? = { }
*/
static char const header_token[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..0f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10..1f
0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0, // 20..2f
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, // 30..3f
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 40..4f
1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1, // 50..5f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 60..6f
1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0, // 70..7f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 80..8f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 90..9f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // a0..af
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // b0..bf
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // c0..cf
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // d0..df
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // e0..ef
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // f0..ff
};
/// Is the character a token
inline bool is_token_char(unsigned char c) {
return (header_token[c] == 1);
}
/// Is the character a non-token
inline bool is_not_token_char(unsigned char c) {
return !header_token[c];
}
/// Is the character whitespace
/**
* whitespace is space (32) or horizontal tab (9)
*/
inline bool is_whitespace_char(unsigned char c) {
return (c == 9 || c == 32);
}
/// Is the character non-whitespace
inline bool is_not_whitespace_char(unsigned char c) {
return (c != 9 && c != 32);
}
/// HTTP Status codes
namespace status_code {
enum value {
uninitialized = 0,
continue_code = 100,
switching_protocols = 101,
ok = 200,
created = 201,
accepted = 202,
non_authoritative_information = 203,
no_content = 204,
reset_content = 205,
partial_content = 206,
multiple_choices = 300,
moved_permanently = 301,
found = 302,
see_other = 303,
not_modified = 304,
use_proxy = 305,
temporary_redirect = 307,
bad_request = 400,
unauthorized = 401,
payment_required = 402,
forbidden = 403,
not_found = 404,
method_not_allowed = 405,
not_acceptable = 406,
proxy_authentication_required = 407,
request_timeout = 408,
conflict = 409,
gone = 410,
length_required = 411,
precondition_failed = 412,
request_entity_too_large = 413,
request_uri_too_long = 414,
unsupported_media_type = 415,
request_range_not_satisfiable = 416,
expectation_failed = 417,
im_a_teapot = 418,
upgrade_required = 426,
precondition_required = 428,
too_many_requests = 429,
request_header_fields_too_large = 431,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503,
gateway_timeout = 504,
http_version_not_supported = 505,
not_extended = 510,
network_authentication_required = 511
};
// TODO: should this be inline?
inline std::string get_string(value c) {
switch (c) {
case uninitialized:
return "Uninitialized";
case continue_code:
return "Continue";
case switching_protocols:
return "Switching Protocols";
case ok:
return "OK";
case created:
return "Created";
case accepted:
return "Accepted";
case non_authoritative_information:
return "Non Authoritative Information";
case no_content:
return "No Content";
case reset_content:
return "Reset Content";
case partial_content:
return "Partial Content";
case multiple_choices:
return "Multiple Choices";
case moved_permanently:
return "Moved Permanently";
case found:
return "Found";
case see_other:
return "See Other";
case not_modified:
return "Not Modified";
case use_proxy:
return "Use Proxy";
case temporary_redirect:
return "Temporary Redirect";
case bad_request:
return "Bad Request";
case unauthorized:
return "Unauthorized";
case payment_required:
return "Payment Required";
case forbidden:
return "Forbidden";
case not_found:
return "Not Found";
case method_not_allowed:
return "Method Not Allowed";
case not_acceptable:
return "Not Acceptable";
case proxy_authentication_required:
return "Proxy Authentication Required";
case request_timeout:
return "Request Timeout";
case conflict:
return "Conflict";
case gone:
return "Gone";
case length_required:
return "Length Required";
case precondition_failed:
return "Precondition Failed";
case request_entity_too_large:
return "Request Entity Too Large";
case request_uri_too_long:
return "Request-URI Too Long";
case unsupported_media_type:
return "Unsupported Media Type";
case request_range_not_satisfiable:
return "Requested Range Not Satisfiable";
case expectation_failed:
return "Expectation Failed";
case im_a_teapot:
return "I'm a teapot";
case upgrade_required:
return "Upgrade Required";
case precondition_required:
return "Precondition Required";
case too_many_requests:
return "Too Many Requests";
case request_header_fields_too_large:
return "Request Header Fields Too Large";
case internal_server_error:
return "Internal Server Error";
case not_implemented:
return "Not Implemented";
case bad_gateway:
return "Bad Gateway";
case service_unavailable:
return "Service Unavailable";
case gateway_timeout:
return "Gateway Timeout";
case http_version_not_supported:
return "HTTP Version Not Supported";
case not_extended:
return "Not Extended";
case network_authentication_required:
return "Network Authentication Required";
default:
return "Unknown";
}
}
}
class exception : public std::exception {
public:
exception(const std::string& log_msg,
status_code::value error_code,
const std::string& error_msg = std::string(),
const std::string& body = std::string())
: m_msg(log_msg)
, m_error_msg(error_msg)
, m_body(body)
, m_error_code(error_code) {}
~exception() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
std::string m_msg;
std::string m_error_msg;
std::string m_body;
status_code::value m_error_code;
};
}
}
#endif // HTTP_CONSTANTS_HPP

View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_IMPL_HPP
#define HTTP_PARSER_IMPL_HPP
#include <algorithm>
#include <cstdlib>
#include <istream>
#include <sstream>
#include <string>
namespace websocketpp {
namespace http {
namespace parser {
inline void parser::set_version(std::string const & version) {
m_version = version;
}
inline std::string const & parser::get_header(std::string const & key) const {
header_list::const_iterator h = m_headers.find(key);
if (h == m_headers.end()) {
return empty_header;
} else {
return h->second;
}
}
inline bool parser::get_header_as_plist(std::string const & key,
parameter_list & out) const
{
header_list::const_iterator it = m_headers.find(key);
if (it == m_headers.end() || it->second.size() == 0) {
return false;
}
return this->parse_parameter_list(it->second,out);
}
inline void parser::append_header(std::string const & key, std::string const &
val)
{
if (std::find_if(key.begin(),key.end(),is_not_token_char) != key.end()) {
throw exception("Invalid header name",status_code::bad_request);
}
if (this->get_header(key).empty()) {
m_headers[key] = val;
} else {
m_headers[key] += ", " + val;
}
}
inline void parser::replace_header(std::string const & key, std::string const &
val)
{
m_headers[key] = val;
}
inline void parser::remove_header(std::string const & key) {
m_headers.erase(key);
}
inline void parser::set_body(std::string const & value) {
if (value.size() == 0) {
remove_header("Content-Length");
m_body.clear();
return;
}
// TODO: should this method respect the max size? If so how should errors
// be indicated?
std::stringstream len;
len << value.size();
replace_header("Content-Length", len.str());
m_body = value;
}
inline bool parser::parse_parameter_list(std::string const & in,
parameter_list & out) const
{
if (in.size() == 0) {
return false;
}
std::string::const_iterator it;
it = extract_parameters(in.begin(),in.end(),out);
return (it == in.begin());
}
inline bool parser::prepare_body() {
if (!get_header("Content-Length").empty()) {
std::string const & cl_header = get_header("Content-Length");
char * end;
// TODO: not 100% sure what the compatibility of this method is. Also,
// I believe this will only work up to 32bit sizes. Is there a need for
// > 4GiB HTTP payloads?
m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10);
if (m_body_bytes_needed > m_body_bytes_max) {
throw exception("HTTP message body too large",
status_code::request_entity_too_large);
}
m_body_encoding = body_encoding::plain;
return true;
} else if (get_header("Transfer-Encoding") == "chunked") {
// TODO
//m_body_encoding = body_encoding::chunked;
return false;
} else {
return false;
}
}
inline size_t parser::process_body(char const * buf, size_t len) {
if (m_body_encoding == body_encoding::plain) {
size_t processed = (std::min)(m_body_bytes_needed,len);
m_body.append(buf,processed);
m_body_bytes_needed -= processed;
return processed;
} else if (m_body_encoding == body_encoding::chunked) {
// TODO:
throw exception("Unexpected body encoding",
status_code::internal_server_error);
} else {
throw exception("Unexpected body encoding",
status_code::internal_server_error);
}
}
inline void parser::process_header(std::string::iterator begin,
std::string::iterator end)
{
std::string::iterator cursor = std::search(
begin,
end,
header_separator,
header_separator + sizeof(header_separator) - 1
);
if (cursor == end) {
throw exception("Invalid header line",status_code::bad_request);
}
append_header(strip_lws(std::string(begin,cursor)),
strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));
}
inline header_list const & parser::get_headers() const {
return m_headers;
}
inline std::string parser::raw_headers() const {
std::stringstream raw;
header_list::const_iterator it;
for (it = m_headers.begin(); it != m_headers.end(); it++) {
raw << it->first << ": " << it->second << "\r\n";
}
return raw.str();
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_IMPL_HPP

View File

@@ -0,0 +1,191 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_REQUEST_IMPL_HPP
#define HTTP_PARSER_REQUEST_IMPL_HPP
#include <algorithm>
#include <sstream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
inline size_t request::consume(char const * buf, size_t len) {
size_t bytes_processed;
if (m_ready) {return 0;}
if (m_body_bytes_needed > 0) {
bytes_processed = process_body(buf,len);
if (body_ready()) {
m_ready = true;
}
return bytes_processed;
}
// copy new header bytes into buffer
m_buf->append(buf,len);
// Search for delimiter in buf. If found read until then. If not read all
std::string::iterator begin = m_buf->begin();
std::string::iterator end;
for (;;) {
// search for line delimiter
end = std::search(
begin,
m_buf->end(),
header_delimiter,
header_delimiter+sizeof(header_delimiter)-1
);
m_header_bytes += (end-begin+sizeof(header_delimiter));
if (m_header_bytes > max_header_size) {
// exceeded max header size
throw exception("Maximum header size exceeded.",
status_code::request_header_fields_too_large);
}
if (end == m_buf->end()) {
// we are out of bytes. Discard the processed bytes and copy the
// remaining unprecessed bytes to the beginning of the buffer
std::copy(begin,end,m_buf->begin());
m_buf->resize(static_cast<std::string::size_type>(end-begin));
m_header_bytes -= m_buf->size();
return len;
}
//the range [begin,end) now represents a line to be processed.
if (end-begin == 0) {
// we got a blank line
if (m_method.empty() || get_header("Host").empty()) {
throw exception("Incomplete Request",status_code::bad_request);
}
bytes_processed = (
len - static_cast<std::string::size_type>(m_buf->end()-end)
+ sizeof(header_delimiter) - 1
);
// frees memory used temporarily during request parsing
m_buf.reset();
// if this was not an upgrade request and has a content length
// continue capturing content-length bytes and expose them as a
// request body.
if (prepare_body()) {
bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);
if (body_ready()) {
m_ready = true;
}
return bytes_processed;
} else {
m_ready = true;
// return number of bytes processed (starting bytes - bytes left)
return bytes_processed;
}
} else {
if (m_method.empty()) {
this->process(begin,end);
} else {
this->process_header(begin,end);
}
}
begin = end+(sizeof(header_delimiter)-1);
}
}
inline std::string request::raw() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
ret << raw_headers() << "\r\n" << m_body;
return ret.str();
}
inline std::string request::raw_head() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
ret << raw_headers() << "\r\n";
return ret.str();
}
inline void request::set_method(std::string const & method) {
if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {
throw exception("Invalid method token.",status_code::bad_request);
}
m_method = method;
}
inline void request::set_uri(std::string const & uri) {
// TODO: validation?
m_uri = uri;
}
inline void request::process(std::string::iterator begin, std::string::iterator
end)
{
std::string::iterator cursor_start = begin;
std::string::iterator cursor_end = std::find(begin,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line1",status_code::bad_request);
}
set_method(std::string(cursor_start,cursor_end));
cursor_start = cursor_end+1;
cursor_end = std::find(cursor_start,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line2",status_code::bad_request);
}
set_uri(std::string(cursor_start,cursor_end));
set_version(std::string(cursor_end+1,end));
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_REQUEST_IMPL_HPP

View File

@@ -0,0 +1,266 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_RESPONSE_IMPL_HPP
#define HTTP_PARSER_RESPONSE_IMPL_HPP
#include <algorithm>
#include <istream>
#include <sstream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
inline size_t response::consume(char const * buf, size_t len) {
if (m_state == DONE) {return 0;}
if (m_state == BODY) {
return this->process_body(buf,len);
}
// copy new header bytes into buffer
m_buf->append(buf,len);
// Search for delimiter in buf. If found read until then. If not read all
std::string::iterator begin = m_buf->begin();
std::string::iterator end = begin;
for (;;) {
// search for delimiter
end = std::search(
begin,
m_buf->end(),
header_delimiter,
header_delimiter + sizeof(header_delimiter) - 1
);
m_header_bytes += (end-begin+sizeof(header_delimiter));
if (m_header_bytes > max_header_size) {
// exceeded max header size
throw exception("Maximum header size exceeded.",
status_code::request_header_fields_too_large);
}
if (end == m_buf->end()) {
// we are out of bytes. Discard the processed bytes and copy the
// remaining unprecessed bytes to the beginning of the buffer
std::copy(begin,end,m_buf->begin());
m_buf->resize(static_cast<std::string::size_type>(end-begin));
m_read += len;
m_header_bytes -= m_buf->size();
return len;
}
//the range [begin,end) now represents a line to be processed.
if (end-begin == 0) {
// we got a blank line
if (m_state == RESPONSE_LINE) {
throw exception("Incomplete Request",status_code::bad_request);
}
// TODO: grab content-length
std::string length = get_header("Content-Length");
if (length.empty()) {
// no content length found, read indefinitely
m_read = 0;
} else {
std::istringstream ss(length);
if ((ss >> m_read).fail()) {
throw exception("Unable to parse Content-Length header",
status_code::bad_request);
}
}
m_state = BODY;
// calc header bytes processed (starting bytes - bytes left)
size_t read = (
len - static_cast<std::string::size_type>(m_buf->end() - end)
+ sizeof(header_delimiter) - 1
);
// if there were bytes left process them as body bytes
if (read < len) {
read += this->process_body(buf+read,(len-read));
}
// frees memory used temporarily during header parsing
m_buf.reset();
return read;
} else {
if (m_state == RESPONSE_LINE) {
this->process(begin,end);
m_state = HEADERS;
} else {
this->process_header(begin,end);
}
}
begin = end+(sizeof(header_delimiter) - 1);
}
}
inline size_t response::consume(std::istream & s) {
char buf[istream_buffer];
size_t bytes_read;
size_t bytes_processed;
size_t total = 0;
while (s.good()) {
s.getline(buf,istream_buffer);
bytes_read = static_cast<size_t>(s.gcount());
if (s.fail() || s.eof()) {
bytes_processed = this->consume(buf,bytes_read);
total += bytes_processed;
if (bytes_processed != bytes_read) {
// problem
break;
}
} else if (s.bad()) {
// problem
break;
} else {
// the delimiting newline was found. Replace the trailing null with
// the newline that was discarded, since our raw consume function
// expects the newline to be be there.
buf[bytes_read-1] = '\n';
bytes_processed = this->consume(buf,bytes_read);
total += bytes_processed;
if (bytes_processed != bytes_read) {
// problem
break;
}
}
}
return total;
}
inline std::string response::raw() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << get_version() << " " << m_status_code << " " << m_status_msg;
ret << "\r\n" << raw_headers() << "\r\n";
ret << m_body;
return ret.str();
}
inline void response::set_status(status_code::value code) {
// TODO: validation?
m_status_code = code;
m_status_msg = get_string(code);
}
inline void response::set_status(status_code::value code, std::string const &
msg)
{
// TODO: validation?
m_status_code = code;
m_status_msg = msg;
}
inline void response::process(std::string::iterator begin,
std::string::iterator end)
{
std::string::iterator cursor_start = begin;
std::string::iterator cursor_end = std::find(begin,end,' ');
if (cursor_end == end) {
throw exception("Invalid response line",status_code::bad_request);
}
set_version(std::string(cursor_start,cursor_end));
cursor_start = cursor_end+1;
cursor_end = std::find(cursor_start,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line",status_code::bad_request);
}
int code;
std::istringstream ss(std::string(cursor_start,cursor_end));
if ((ss >> code).fail()) {
throw exception("Unable to parse response code",status_code::bad_request);
}
set_status(status_code::value(code),std::string(cursor_end+1,end));
}
inline size_t response::process_body(char const * buf, size_t len) {
// If no content length was set then we read forever and never set m_ready
if (m_read == 0) {
//m_body.append(buf,len);
//return len;
m_state = DONE;
return 0;
}
// Otherwise m_read is the number of bytes left.
size_t to_read;
if (len >= m_read) {
// if we have more bytes than we need read, read only the amount needed
// then set done state
to_read = m_read;
m_state = DONE;
} else {
// we need more bytes than are available, read them all
to_read = len;
}
m_body.append(buf,to_read);
m_read -= to_read;
return to_read;
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_RESPONSE_IMPL_HPP

View File

@@ -0,0 +1,629 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_HPP
#define HTTP_PARSER_HPP
#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <websocketpp/utilities.hpp>
#include <websocketpp/http/constants.hpp>
namespace websocketpp {
namespace http {
namespace parser {
namespace state {
enum value {
method,
resource,
version,
headers
};
}
namespace body_encoding {
enum value {
unknown,
plain,
chunked
};
}
typedef std::map<std::string, std::string, utility::ci_less > header_list;
/// Read and return the next token in the stream
/**
* Read until a non-token character is found and then return the token and
* iterator to the next character to read
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return A pair containing the token and an iterator to the next character in
* the stream
*/
template <typename InputIterator>
std::pair<std::string,InputIterator> extract_token(InputIterator begin,
InputIterator end)
{
InputIterator it = std::find_if(begin,end,&is_not_token_char);
return std::make_pair(std::string(begin,it),it);
}
/// Read and return the next quoted string in the stream
/**
* Read a double quoted string starting at `begin`. The quotes themselves are
* stripped. The quoted value is returned along with an iterator to the next
* character to read
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return A pair containing the string read and an iterator to the next
* character in the stream
*/
template <typename InputIterator>
std::pair<std::string,InputIterator> extract_quoted_string(InputIterator begin,
InputIterator end)
{
std::string s;
if (end == begin) {
return std::make_pair(s,begin);
}
if (*begin != '"') {
return std::make_pair(s,begin);
}
InputIterator cursor = begin+1;
InputIterator marker = cursor;
cursor = std::find(cursor,end,'"');
while (cursor != end) {
// either this is the end or a quoted string
if (*(cursor-1) == '\\') {
s.append(marker,cursor-1);
s.append(1,'"');
++cursor;
marker = cursor;
} else {
s.append(marker,cursor);
++cursor;
return std::make_pair(s,cursor);
}
cursor = std::find(cursor,end,'"');
}
return std::make_pair("",begin);
}
/// Read and discard one unit of linear whitespace
/**
* Read one unit of linear white space and return the iterator to the character
* afterwards. If `begin` is returned, no whitespace was extracted.
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return An iterator to the character after the linear whitespace read
*/
template <typename InputIterator>
InputIterator extract_lws(InputIterator begin, InputIterator end) {
InputIterator it = begin;
// strip leading CRLF
if (end-begin > 2 && *begin == '\r' && *(begin+1) == '\n' &&
is_whitespace_char(static_cast<unsigned char>(*(begin+2))))
{
it+=3;
}
it = std::find_if(it,end,&is_not_whitespace_char);
return it;
}
/// Read and discard linear whitespace
/**
* Read linear white space until a non-lws character is read and return an
* iterator to that character. If `begin` is returned, no whitespace was
* extracted.
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return An iterator to the character after the linear whitespace read
*/
template <typename InputIterator>
InputIterator extract_all_lws(InputIterator begin, InputIterator end) {
InputIterator old_it;
InputIterator new_it = begin;
do {
// Pull value from previous iteration
old_it = new_it;
// look ahead another pass
new_it = extract_lws(old_it,end);
} while (new_it != end && old_it != new_it);
return new_it;
}
/// Extract HTTP attributes
/**
* An http attributes list is a semicolon delimited list of key value pairs in
* the format: *( ";" attribute "=" value ) where attribute is a token and value
* is a token or quoted string.
*
* Attributes extracted are appended to the supplied attributes list
* `attributes`.
*
* @param [in] begin An iterator to the beginning of the sequence
* @param [in] end An iterator to the end of the sequence
* @param [out] attributes A reference to the attributes list to append
* attribute/value pairs extracted to
* @return An iterator to the character after the last atribute read
*/
template <typename InputIterator>
InputIterator extract_attributes(InputIterator begin, InputIterator end,
attribute_list & attributes)
{
InputIterator cursor;
bool first = true;
if (begin == end) {
return begin;
}
cursor = begin;
std::pair<std::string,InputIterator> ret;
while (cursor != end) {
std::string name;
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
break;
}
if (first) {
// ignore this check for the very first pass
first = false;
} else {
if (*cursor == ';') {
// advance past the ';'
++cursor;
} else {
// non-semicolon in this position indicates end end of the
// attribute list, break and return.
break;
}
}
cursor = http::parser::extract_all_lws(cursor,end);
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error: expected a token
return begin;
} else {
name = ret.first;
cursor = ret.second;
}
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end || *cursor != '=') {
// if there is an equals sign, read the attribute value. Otherwise
// record a blank value and continue
attributes[name].clear();
continue;
}
// advance past the '='
++cursor;
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
// error: expected a token or quoted string
return begin;
}
ret = http::parser::extract_quoted_string(cursor,end);
if (ret.second != cursor) {
attributes[name] = ret.first;
cursor = ret.second;
continue;
}
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error : expected token or quoted string
return begin;
} else {
attributes[name] = ret.first;
cursor = ret.second;
}
}
return cursor;
}
/// Extract HTTP parameters
/**
* An http parameters list is a comma delimited list of tokens followed by
* optional semicolon delimited attributes lists.
*
* Parameters extracted are appended to the supplied parameters list
* `parameters`.
*
* @param [in] begin An iterator to the beginning of the sequence
* @param [in] end An iterator to the end of the sequence
* @param [out] parameters A reference to the parameters list to append
* paramter values extracted to
* @return An iterator to the character after the last parameter read
*/
template <typename InputIterator>
InputIterator extract_parameters(InputIterator begin, InputIterator end,
parameter_list &parameters)
{
InputIterator cursor;
if (begin == end) {
// error: expected non-zero length range
return begin;
}
cursor = begin;
std::pair<std::string,InputIterator> ret;
/**
* LWS
* token
* LWS
* *(";" method-param)
* LWS
* ,=loop again
*/
while (cursor != end) {
std::string parameter_name;
attribute_list attributes;
// extract any stray whitespace
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {break;}
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error: expected a token
return begin;
} else {
parameter_name = ret.first;
cursor = ret.second;
}
// Safe break point, insert parameter with blank attributes and exit
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
//parameters[parameter_name] = attributes;
parameters.push_back(std::make_pair(parameter_name,attributes));
break;
}
// If there is an attribute list, read it in
if (*cursor == ';') {
InputIterator acursor;
++cursor;
acursor = http::parser::extract_attributes(cursor,end,attributes);
if (acursor == cursor) {
// attribute extraction ended in syntax error
return begin;
}
cursor = acursor;
}
// insert parameter into output list
//parameters[parameter_name] = attributes;
parameters.push_back(std::make_pair(parameter_name,attributes));
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {break;}
// if next char is ',' then read another parameter, else stop
if (*cursor != ',') {
break;
}
// advance past comma
++cursor;
if (cursor == end) {
// expected more bytes after a comma
return begin;
}
}
return cursor;
}
inline std::string strip_lws(std::string const & input) {
std::string::const_iterator begin = extract_all_lws(input.begin(),input.end());
if (begin == input.end()) {
return std::string();
}
std::string::const_reverse_iterator rbegin = extract_all_lws(input.rbegin(),input.rend());
if (rbegin == input.rend()) {
return std::string();
}
return std::string(begin,rbegin.base());
}
/// Base HTTP parser
/**
* Includes methods and data elements common to all types of HTTP messages such
* as headers, versions, bodies, etc.
*/
class parser {
public:
parser()
: m_header_bytes(0)
, m_body_bytes_needed(0)
, m_body_bytes_max(max_body_size)
, m_body_encoding(body_encoding::unknown) {}
/// Get the HTTP version string
/**
* @return The version string for this parser
*/
std::string const & get_version() const {
return m_version;
}
/// Set HTTP parser Version
/**
* Input should be in format: HTTP/x.y where x and y are positive integers.
* @todo Does this method need any validation?
*
* @param [in] version The value to set the HTTP version to.
*/
void set_version(std::string const & version);
/// Get the value of an HTTP header
/**
* @todo Make this method case insensitive.
*
* @param [in] key The name/key of the header to get.
* @return The value associated with the given HTTP header key.
*/
std::string const & get_header(std::string const & key) const;
/// Extract an HTTP parameter list from a parser header.
/**
* If the header requested doesn't exist or exists and is empty the
* parameter list is valid (but empty).
*
* @param [in] key The name/key of the HTTP header to use as input.
* @param [out] out The parameter list to store extracted parameters in.
* @return Whether or not the input was a valid parameter list.
*/
bool get_header_as_plist(std::string const & key, parameter_list & out)
const;
/// Return a list of all HTTP headers
/**
* Return a list of all HTTP headers
*
* @since 0.8.0
*
* @return A list of all HTTP headers
*/
header_list const & get_headers() const;
/// Append a value to an existing HTTP header
/**
* This method will set the value of the HTTP header `key` with the
* indicated value. If a header with the name `key` already exists, `val`
* will be appended to the existing value.
*
* @todo Make this method case insensitive.
* @todo Should there be any restrictions on which keys are allowed?
* @todo Exception free varient
*
* @see replace_header
*
* @param [in] key The name/key of the header to append to.
* @param [in] val The value to append.
*/
void append_header(std::string const & key, std::string const & val);
/// Set a value for an HTTP header, replacing an existing value
/**
* This method will set the value of the HTTP header `key` with the
* indicated value. If a header with the name `key` already exists, `val`
* will replace the existing value.
*
* @todo Make this method case insensitive.
* @todo Should there be any restrictions on which keys are allowed?
* @todo Exception free varient
*
* @see append_header
*
* @param [in] key The name/key of the header to append to.
* @param [in] val The value to append.
*/
void replace_header(std::string const & key, std::string const & val);
/// Remove a header from the parser
/**
* Removes the header entirely from the parser. This is different than
* setting the value of the header to blank.
*
* @todo Make this method case insensitive.
*
* @param [in] key The name/key of the header to remove.
*/
void remove_header(std::string const & key);
/// Get HTTP body
/**
* Gets the body of the HTTP object
*
* @return The body of the HTTP message.
*/
std::string const & get_body() const {
return m_body;
}
/// Set body content
/**
* Set the body content of the HTTP response to the parameter string. Note
* set_body will also set the Content-Length HTTP header to the appropriate
* value. If you want the Content-Length header to be something else, do so
* via replace_header("Content-Length") after calling set_body()
*
* @param value String data to include as the body content.
*/
void set_body(std::string const & value);
/// Get body size limit
/**
* Retrieves the maximum number of bytes to parse & buffer before canceling
* a request.
*
* @since 0.5.0
*
* @return The maximum length of a message body.
*/
size_t get_max_body_size() const {
return m_body_bytes_max;
}
/// Set body size limit
/**
* Set the maximum number of bytes to parse and buffer before canceling a
* request.
*
* @since 0.5.0
*
* @param value The size to set the max body length to.
*/
void set_max_body_size(size_t value) {
m_body_bytes_max = value;
}
/// Extract an HTTP parameter list from a string.
/**
* @param [in] in The input string.
* @param [out] out The parameter list to store extracted parameters in.
* @return Whether or not the input was a valid parameter list.
*/
bool parse_parameter_list(std::string const & in, parameter_list & out)
const;
protected:
/// Process a header line
/**
* @todo Update this method to be exception free.
*
* @param [in] begin An iterator to the beginning of the sequence.
* @param [in] end An iterator to the end of the sequence.
*/
void process_header(std::string::iterator begin, std::string::iterator end);
/// Prepare the parser to begin parsing body data
/**
* Inspects headers to determine if the message has a body that needs to be
* read. If so, sets up the necessary state, otherwise returns false. If
* this method returns true and loading the message body is desired call
* `process_body` until it returns zero bytes or an error.
*
* Must not be called until after all headers have been processed.
*
* @since 0.5.0
*
* @return True if more bytes are needed to load the body, false otherwise.
*/
bool prepare_body();
/// Process body data
/**
* Parses body data.
*
* @since 0.5.0
*
* @param [in] begin An iterator to the beginning of the sequence.
* @param [in] end An iterator to the end of the sequence.
* @return The number of bytes processed
*/
size_t process_body(char const * buf, size_t len);
/// Check if the parser is done parsing the body
/**
* Behavior before a call to `prepare_body` is undefined.
*
* @since 0.5.0
*
* @return True if the message body has been completed loaded.
*/
bool body_ready() const {
return (m_body_bytes_needed == 0);
}
/// Generate and return the HTTP headers as a string
/**
* Each headers will be followed by the \r\n sequence including the last one.
* A second \r\n sequence (blank header) is not appended by this method
*
* @return The HTTP headers as a string.
*/
std::string raw_headers() const;
std::string m_version;
header_list m_headers;
size_t m_header_bytes;
std::string m_body;
size_t m_body_bytes_needed;
size_t m_body_bytes_max;
body_encoding::value m_body_encoding;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/parser.hpp>
#endif // HTTP_PARSER_HPP

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_REQUEST_HPP
#define HTTP_PARSER_REQUEST_HPP
#include <string>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
/// Stores, parses, and manipulates HTTP requests
/**
* http::request provides the following functionality for working with HTTP
* requests.
*
* - Initialize request via manually setting each element
* - Initialize request via reading raw bytes and parsing
* - Once initialized, access individual parsed elements
* - Once initialized, read entire request as raw bytes
*/
class request : public parser {
public:
typedef request type;
typedef lib::shared_ptr<type> ptr;
request()
: m_buf(lib::make_shared<std::string>())
, m_ready(false) {}
/// Process bytes in the input buffer
/**
* Process up to len bytes from input buffer buf. Returns the number of
* bytes processed. Bytes left unprocessed means bytes left over after the
* final header delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* request and the full headers need not be available before processing can
* begin. If the end of the request was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed requests, incomplete requests, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(char const * buf, size_t len);
/// Returns whether or not the request is ready for reading.
bool ready() const {
return m_ready;
}
/// Returns the full raw request (including the body)
std::string raw() const;
/// Returns the raw request headers only (similar to an HTTP HEAD request)
std::string raw_head() const;
/// Set the HTTP method. Must be a valid HTTP token
void set_method(std::string const & method);
/// Return the request method
std::string const & get_method() const {
return m_method;
}
/// Set the HTTP uri. Must be a valid HTTP uri
void set_uri(std::string const & uri);
/// Return the requested URI
std::string const & get_uri() const {
return m_uri;
}
private:
/// Helper function for message::consume. Process request line
void process(std::string::iterator begin, std::string::iterator end);
lib::shared_ptr<std::string> m_buf;
std::string m_method;
std::string m_uri;
bool m_ready;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/request.hpp>
#endif // HTTP_PARSER_REQUEST_HPP

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_RESPONSE_HPP
#define HTTP_PARSER_RESPONSE_HPP
#include <iostream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
/// Stores, parses, and manipulates HTTP responses
/**
* http::response provides the following functionality for working with HTTP
* responses.
*
* - Initialize response via manually setting each element
* - Initialize response via reading raw bytes and parsing
* - Once initialized, access individual parsed elements
* - Once initialized, read entire response as raw bytes
*
* http::response checks for header completeness separately from the full
* response. Once the header is complete, the Content-Length header is read to
* determine when to stop reading body bytes. If no Content-Length is present
* ready() will never return true. It is the responsibility of the caller to
* consume to determine when the response is complete (ie when the connection
* terminates, or some other metric).
*/
class response : public parser {
public:
typedef response type;
typedef lib::shared_ptr<type> ptr;
response()
: m_read(0)
, m_buf(lib::make_shared<std::string>())
, m_status_code(status_code::uninitialized)
, m_state(RESPONSE_LINE) {}
/// Process bytes in the input buffer
/**
* Process up to len bytes from input buffer buf. Returns the number of
* bytes processed. Bytes left unprocessed means bytes left over after the
* final header delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* response and the full headers need not be available before processing can
* begin. If the end of the response was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed responses, incomplete responses, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(char const * buf, size_t len);
/// Process bytes in the input buffer (istream version)
/**
* Process bytes from istream s. Returns the number of bytes processed.
* Bytes left unprocessed means bytes left over after the final header
* delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* response and the full headers need not be available before processing can
* begin. If the end of the response was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed responses, incomplete responses, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(std::istream & s);
/// Returns true if the response is ready.
/**
* @note will never return true if the content length header is not present
*/
bool ready() const {
return m_state == DONE;
}
/// Returns true if the response headers are fully parsed.
bool headers_ready() const {
return (m_state == BODY || m_state == DONE);
}
/// Returns the full raw response
std::string raw() const;
/// Set response status code and message
/**
* Sets the response status code to `code` and looks up the corresponding
* message for standard codes. Non-standard codes will be entered as Unknown
* use set_status(status_code::value,std::string) overload to set both
* values explicitly.
*
* @param code Code to set
* @param msg Message to set
*/
void set_status(status_code::value code);
/// Set response status code and message
/**
* Sets the response status code and message to independent custom values.
* use set_status(status_code::value) to set the code and have the standard
* message be automatically set.
*
* @param code Code to set
* @param msg Message to set
*/
void set_status(status_code::value code, std::string const & msg);
/// Return the response status code
status_code::value get_status_code() const {
return m_status_code;
}
/// Return the response status message
const std::string& get_status_msg() const {
return m_status_msg;
}
private:
/// Helper function for consume. Process response line
void process(std::string::iterator begin, std::string::iterator end);
/// Helper function for processing body bytes
size_t process_body(char const * buf, size_t len);
enum state {
RESPONSE_LINE = 0,
HEADERS = 1,
BODY = 2,
DONE = 3
};
std::string m_status_msg;
size_t m_read;
lib::shared_ptr<std::string> m_buf;
status_code::value m_status_code;
state m_state;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/response.hpp>
#endif // HTTP_PARSER_RESPONSE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,269 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_IMPL_HPP
#define WEBSOCKETPP_ENDPOINT_IMPL_HPP
#include <string>
namespace websocketpp {
template <typename connection, typename config>
typename endpoint<connection,config>::connection_ptr
endpoint<connection,config>::create_connection() {
m_alog->write(log::alevel::devel,"create_connection");
//scoped_lock_type lock(m_state_lock);
/*if (m_state == STOPPING || m_state == STOPPED) {
return connection_ptr();
}*/
//scoped_lock_type guard(m_mutex);
// Create a connection on the heap and manage it using a shared pointer
connection_ptr con = lib::make_shared<connection_type>(m_is_server,
m_user_agent, m_alog, m_elog, lib::ref(m_rng));
connection_weak_ptr w(con);
// Create a weak pointer on the heap using that 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)));
con->set_handle(w);
// Copy default handlers from the endpoint
con->set_open_handler(m_open_handler);
con->set_close_handler(m_close_handler);
con->set_fail_handler(m_fail_handler);
con->set_ping_handler(m_ping_handler);
con->set_pong_handler(m_pong_handler);
con->set_pong_timeout_handler(m_pong_timeout_handler);
con->set_interrupt_handler(m_interrupt_handler);
con->set_http_handler(m_http_handler);
con->set_validate_handler(m_validate_handler);
con->set_message_handler(m_message_handler);
if (m_open_handshake_timeout_dur != config::timeout_open_handshake) {
con->set_open_handshake_timeout(m_open_handshake_timeout_dur);
}
if (m_close_handshake_timeout_dur != config::timeout_close_handshake) {
con->set_close_handshake_timeout(m_close_handshake_timeout_dur);
}
if (m_pong_timeout_dur != config::timeout_pong) {
con->set_pong_timeout(m_pong_timeout_dur);
}
if (m_max_message_size != config::max_message_size) {
con->set_max_message_size(m_max_message_size);
}
con->set_max_http_body_size(m_max_http_body_size);
lib::error_code ec;
ec = transport_type::init(con);
if (ec) {
m_elog->write(log::elevel::fatal,ec.message());
return connection_ptr();
}
return con;
}
template <typename connection, typename config>
void endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
m_alog->write(log::alevel::devel,"Interrupting connection");
ec = con->interrupt();
}
template <typename connection, typename config>
void endpoint<connection,config>::interrupt(connection_hdl hdl) {
lib::error_code ec;
interrupt(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::pause_reading(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->pause_reading();
}
template <typename connection, typename config>
void endpoint<connection,config>::pause_reading(connection_hdl hdl) {
lib::error_code ec;
pause_reading(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::resume_reading(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->resume_reading();
}
template <typename connection, typename config>
void endpoint<connection,config>::resume_reading(connection_hdl hdl) {
lib::error_code ec;
resume_reading(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->send_http_response(ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl) {
lib::error_code ec;
send_http_response(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(payload,op);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op)
{
lib::error_code ec;
send(hdl,payload,op,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
size_t len, frame::opcode::value op, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(payload,len,op);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
size_t len, frame::opcode::value op)
{
lib::error_code ec;
send(hdl,payload,len,op,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(msg);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg) {
lib::error_code ec;
send(hdl,msg,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
const code, std::string const & reason,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->close(code,reason,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
const code, std::string const & reason)
{
lib::error_code ec;
close(hdl,code,reason,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
payload, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->ping(payload,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const & payload)
{
lib::error_code ec;
ping(hdl,payload,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->pong(payload,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload)
{
lib::error_code ec;
pong(hdl,payload,ec);
if (ec) { throw exception(ec); }
}
} // namespace websocketpp
#endif // WEBSOCKETPP_ENDPOINT_IMPL_HPP

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2014, 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_UTILITIES_IMPL_HPP
#define WEBSOCKETPP_UTILITIES_IMPL_HPP
#include <algorithm>
#include <string>
namespace websocketpp {
namespace utility {
inline std::string to_lower(std::string const & in) {
std::string out = in;
std::transform(out.begin(),out.end(),out.begin(),::tolower);
return out;
}
inline std::string to_hex(std::string const & input) {
std::string output;
std::string hex = "0123456789ABCDEF";
for (size_t i = 0; i < input.size(); i++) {
output += hex[(input[i] & 0xF0) >> 4];
output += hex[input[i] & 0x0F];
output += " ";
}
return output;
}
inline std::string to_hex(uint8_t const * input, size_t length) {
std::string output;
std::string hex = "0123456789ABCDEF";
for (size_t i = 0; i < length; i++) {
output += hex[(input[i] & 0xF0) >> 4];
output += hex[input[i] & 0x0F];
output += " ";
}
return output;
}
inline std::string to_hex(const char* input,size_t length) {
return to_hex(reinterpret_cast<const uint8_t*>(input),length);
}
inline std::string string_replace_all(std::string subject, std::string const &
search, std::string const & replace)
{
size_t pos = 0;
while((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
} // namespace utility
} // namespace websocketpp
#endif // WEBSOCKETPP_UTILITIES_IMPL_HPP

View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2014, 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_LOGGER_BASIC_HPP
#define WEBSOCKETPP_LOGGER_BASIC_HPP
/* Need a way to print a message to the log
*
* - timestamps
* - channels
* - thread safe
* - output to stdout or file
* - selective output channels, both compile time and runtime
* - named channels
* - ability to test whether a log message will be printed at compile time
*
*/
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/time.hpp>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <string>
namespace websocketpp {
namespace log {
/// Basic logger that outputs to an ostream
template <typename concurrency, typename names>
class basic {
public:
basic<concurrency,names>(channel_type_hint::value h =
channel_type_hint::access)
: m_static_channels(0xffffffff)
, m_dynamic_channels(0)
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
basic<concurrency,names>(std::ostream * out)
: m_static_channels(0xffffffff)
, m_dynamic_channels(0)
, m_out(out) {}
basic<concurrency,names>(level c, channel_type_hint::value h =
channel_type_hint::access)
: m_static_channels(c)
, m_dynamic_channels(0)
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
basic<concurrency,names>(level c, std::ostream * out)
: m_static_channels(c)
, m_dynamic_channels(0)
, m_out(out) {}
/// Destructor
~basic<concurrency,names>() {}
/// Copy constructor
basic<concurrency,names>(basic<concurrency,names> const & other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
basic<concurrency,names>(basic<concurrency,names> && other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
void set_ostream(std::ostream * out = &std::cout) {
m_out = out;
}
void set_channels(level channels) {
if (channels == names::none) {
clear_channels(names::all);
return;
}
scoped_lock_type lock(m_lock);
m_dynamic_channels |= (channels & m_static_channels);
}
void clear_channels(level channels) {
scoped_lock_type lock(m_lock);
m_dynamic_channels &= ~channels;
}
/// Write a string message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, std::string const & msg) {
scoped_lock_type lock(m_lock);
if (!this->dynamic_test(channel)) { return; }
*m_out << "[" << timestamp << "] "
<< "[" << names::channel_name(channel) << "] "
<< msg << "\n";
m_out->flush();
}
/// Write a cstring message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, char const * msg) {
scoped_lock_type lock(m_lock);
if (!this->dynamic_test(channel)) { return; }
*m_out << "[" << timestamp << "] "
<< "[" << names::channel_name(channel) << "] "
<< msg << "\n";
m_out->flush();
}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {
return ((channel & m_static_channels) != 0);
}
bool dynamic_test(level channel) {
return ((channel & m_dynamic_channels) != 0);
}
protected:
typedef typename concurrency::scoped_lock_type scoped_lock_type;
typedef typename concurrency::mutex_type mutex_type;
mutex_type m_lock;
private:
// The timestamp does not include the time zone, because on Windows with the
// default registry settings, the time zone would be written out in full,
// which would be obnoxiously verbose.
//
// TODO: find a workaround for this or make this format user settable
static std::ostream & timestamp(std::ostream & os) {
std::time_t t = std::time(NULL);
std::tm lt = lib::localtime(t);
#ifdef _WEBSOCKETPP_PUTTIME_
return os << std::put_time(&lt,"%Y-%m-%d %H:%M:%S");
#else // Falls back to strftime, which requires a temporary copy of the string.
char buffer[20];
size_t result = std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",&lt);
return os << (result == 0 ? "Unknown" : buffer);
#endif
}
level const m_static_channels;
level m_dynamic_channels;
std::ostream * m_out;
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_BASIC_HPP

View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2014, 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_LOGGER_LEVELS_HPP
#define WEBSOCKETPP_LOGGER_LEVELS_HPP
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
namespace log {
/// Type of a channel package
typedef uint32_t level;
/// Package of values for hinting at the nature of a given logger.
/**
* Used by the library to signal to the logging class a hint that it can use to
* set itself up. For example, the `access` hint indicates that it is an access
* log that might be suitable for being printed to an access log file or to cout
* whereas `error` might be suitable for an error log file or cerr.
*/
struct channel_type_hint {
/// Type of a channel type hint value
typedef uint32_t value;
/// No information
static value const none = 0;
/// Access log
static value const access = 1;
/// Error log
static value const error = 2;
};
/// Package of log levels for logging errors
struct elevel {
/// Special aggregate value representing "no levels"
static level const none = 0x0;
/// Low level debugging information (warning: very chatty)
static level const devel = 0x1;
/// Information about unusual system states or other minor internal library
/// problems, less chatty than devel.
static level const library = 0x2;
/// Information about minor configuration problems or additional information
/// about other warnings.
static level const info = 0x4;
/// Information about important problems not severe enough to terminate
/// connections.
static level const warn = 0x8;
/// Recoverable error. Recovery may mean cleanly closing the connection with
/// an appropriate error code to the remote endpoint.
static level const rerror = 0x10;
/// Unrecoverable error. This error will trigger immediate unclean
/// termination of the connection or endpoint.
static level const fatal = 0x20;
/// Special aggregate value representing "all levels"
static level const all = 0xffffffff;
/// Get the textual name of a channel given a channel id
/**
* The id must be that of a single channel. Passing an aggregate channel
* package results in undefined behavior.
*
* @param channel The channel id to look up.
*
* @return The name of the specified channel.
*/
static char const * channel_name(level channel) {
switch(channel) {
case devel:
return "devel";
case library:
return "library";
case info:
return "info";
case warn:
return "warning";
case rerror:
return "error";
case fatal:
return "fatal";
default:
return "unknown";
}
}
};
/// Package of log levels for logging access events
struct alevel {
/// Special aggregate value representing "no levels"
static level const none = 0x0;
/// Information about new connections
/**
* One line for each new connection that includes a host of information
* including: the remote address, websocket version, requested resource,
* http code, remote user agent
*/
static level const connect = 0x1;
/// One line for each closed connection. Includes closing codes and reasons.
static level const disconnect = 0x2;
/// One line per control frame
static level const control = 0x4;
/// One line per frame, includes the full frame header
static level const frame_header = 0x8;
/// One line per frame, includes the full message payload (warning: chatty)
static level const frame_payload = 0x10;
/// Reserved
static level const message_header = 0x20;
/// Reserved
static level const message_payload = 0x40;
/// Reserved
static level const endpoint = 0x80;
/// Extra information about opening handshakes
static level const debug_handshake = 0x100;
/// Extra information about closing handshakes
static level const debug_close = 0x200;
/// Development messages (warning: very chatty)
static level const devel = 0x400;
/// Special channel for application specific logs. Not used by the library.
static level const app = 0x800;
/// Access related to HTTP requests
static level const http = 0x1000;
/// One line for each failed WebSocket connection with details
static level const fail = 0x2000;
/// Aggregate package representing the commonly used core access channels
/// Connect, Disconnect, Fail, and HTTP
static level const access_core = 0x00003003;
/// Special aggregate value representing "all levels"
static level const all = 0xffffffff;
/// Get the textual name of a channel given a channel id
/**
* Get the textual name of a channel given a channel id. The id must be that
* of a single channel. Passing an aggregate channel package results in
* undefined behavior.
*
* @param channel The channelid to look up.
*
* @return The name of the specified channel.
*/
static char const * channel_name(level channel) {
switch(channel) {
case connect:
return "connect";
case disconnect:
return "disconnect";
case control:
return "control";
case frame_header:
return "frame_header";
case frame_payload:
return "frame_payload";
case message_header:
return "message_header";
case message_payload:
return "message_payload";
case endpoint:
return "endpoint";
case debug_handshake:
return "debug_handshake";
case debug_close:
return "debug_close";
case devel:
return "devel";
case app:
return "application";
case http:
return "http";
case fail:
return "fail";
default:
return "unknown";
}
}
};
} // logger
} // websocketpp
#endif //WEBSOCKETPP_LOGGER_LEVELS_HPP

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2014, 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_LOGGER_STUB_HPP
#define WEBSOCKETPP_LOGGER_STUB_HPP
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <string>
namespace websocketpp {
namespace log {
/// Stub logger that ignores all input
class stub {
public:
/// Construct the logger
/**
* @param hint A channel type specific hint for how to construct the logger
*/
explicit stub(channel_type_hint::value) {}
/// Construct the logger
/**
* @param default_channels A set of channels to statically enable
* @param hint A channel type specific hint for how to construct the logger
*/
stub(level, channel_type_hint::value) {}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}
/// Dynamically enable the given list of channels
/**
* All operations on the stub logger are no-ops and all arguments are
* ignored
*
* @param channels The package of channels to enable
*/
void set_channels(level) {}
/// Dynamically disable the given list of channels
/**
* All operations on the stub logger are no-ops and all arguments are
* ignored
*
* @param channels The package of channels to disable
*/
void clear_channels(level) {}
/// Write a string message to the given channel
/**
* Writing on the stub logger is a no-op and all arguments are ignored
*
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level, std::string const &) {}
/// Write a cstring message to the given channel
/**
* Writing on the stub logger is a no-op and all arguments are ignored
*
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level, char const *) {}
/// Test whether a channel is statically enabled
/**
* The stub logger has no channels so all arguments are ignored and
* `static_test` always returns false.
*
* @param channel The package of channels to test
*/
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const {
return false;
}
/// Test whether a channel is dynamically enabled
/**
* The stub logger has no channels so all arguments are ignored and
* `dynamic_test` always returns false.
*
* @param channel The package of channels to test
*/
bool dynamic_test(level) {
return false;
}
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_STUB_HPP

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2014, 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.
*
*
* The initial version of this logging policy was contributed to the WebSocket++
* project by Tom Hughes.
*/
#ifndef WEBSOCKETPP_LOGGER_SYSLOG_HPP
#define WEBSOCKETPP_LOGGER_SYSLOG_HPP
#include <syslog.h>
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/logger/levels.hpp>
namespace websocketpp {
namespace log {
/// Basic logger that outputs to syslog
template <typename concurrency, typename names>
class syslog : public basic<concurrency, names> {
public:
typedef basic<concurrency, names> base;
/// Construct the logger
/**
* @param hint A channel type specific hint for how to construct the logger
*/
syslog<concurrency,names>(channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(hint), m_channel_type_hint(hint) {}
/// Construct the logger
/**
* @param channels A set of channels to statically enable
* @param hint A channel type specific hint for how to construct the logger
*/
syslog<concurrency,names>(level channels, channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {}
/// Write a string message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, std::string const & msg) {
write(channel, msg.c_str());
}
/// Write a cstring message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, char const * msg) {
scoped_lock_type lock(base::m_lock);
if (!this->dynamic_test(channel)) { return; }
::syslog(syslog_priority(channel), "[%s] %s",
names::channel_name(channel), msg);
}
private:
typedef typename base::scoped_lock_type scoped_lock_type;
/// The default level is used for all access logs and any error logs that
/// don't trivially map to one of the standard syslog levels.
static int const default_level = LOG_INFO;
/// retrieve the syslog priority code given a WebSocket++ channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
int syslog_priority(level channel) const {
if (m_channel_type_hint == channel_type_hint::access) {
return syslog_priority_access(channel);
} else {
return syslog_priority_error(channel);
}
}
/// retrieve the syslog priority code given a WebSocket++ error channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
int syslog_priority_error(level channel) const {
switch (channel) {
case elevel::devel:
return LOG_DEBUG;
case elevel::library:
return LOG_DEBUG;
case elevel::info:
return LOG_INFO;
case elevel::warn:
return LOG_WARNING;
case elevel::rerror:
return LOG_ERR;
case elevel::fatal:
return LOG_CRIT;
default:
return default_level;
}
}
/// retrieve the syslog priority code given a WebSocket++ access channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
_WEBSOCKETPP_CONSTEXPR_TOKEN_ int syslog_priority_access(level) const {
return default_level;
}
channel_type_hint::value m_channel_type_hint;
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_SYSLOG_HPP

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_ALLOC_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/frame.hpp>
namespace websocketpp {
namespace message_buffer {
namespace alloc {
/// A connection message manager that allocates a new message for each
/// request.
template <typename message>
class con_msg_manager
: public lib::enable_shared_from_this<con_msg_manager<message> >
{
public:
typedef con_msg_manager<message> type;
typedef lib::shared_ptr<con_msg_manager> ptr;
typedef lib::weak_ptr<con_msg_manager> weak_ptr;
typedef typename message::ptr message_ptr;
/// Get an empty message buffer
/**
* @return A shared pointer to an empty new message
*/
message_ptr get_message() {
return message_ptr(lib::make_shared<message>(type::shared_from_this()));
}
/// Get a message buffer with specified size and opcode
/**
* @param op The opcode to use
* @param size Minimum size in bytes to request for the message payload.
*
* @return A shared pointer to a new message with specified size.
*/
message_ptr get_message(frame::opcode::value op,size_t size) {
return message_ptr(lib::make_shared<message>(type::shared_from_this(),op,size));
}
/// Recycle a message
/**
* This method shouldn't be called. If it is, return false to indicate an
* error. The rest of the method recycle chain should notice this and free
* the memory.
*
* @param msg The message to be recycled.
*
* @return true if the message was successfully recycled, false otherwse.
*/
bool recycle(message *) {
return false;
}
};
/// An endpoint message manager that allocates a new manager for each
/// connection.
template <typename con_msg_manager>
class endpoint_msg_manager {
public:
typedef typename con_msg_manager::ptr con_msg_man_ptr;
/// Get a pointer to a connection message manager
/**
* @return A pointer to the requested connection message manager.
*/
con_msg_man_ptr get_manager() const {
return con_msg_man_ptr(lib::make_shared<con_msg_manager>());
}
};
} // namespace alloc
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP

View File

@@ -0,0 +1,340 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_MESSAGE_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/frame.hpp>
#include <string>
namespace websocketpp {
namespace message_buffer {
/* # message:
* object that stores a message while it is being sent or received. Contains
* the message payload itself, the message header, the extension data, and the
* opcode.
*
* # connection_message_manager:
* An object that manages all of the message_buffers associated with a given
* connection. Implements the get_message_buffer(size) method that returns
* a message buffer at least size bytes long.
*
* Message buffers are reference counted with shared ownership semantics. Once
* requested from the manager the requester and it's associated downstream code
* may keep a pointer to the message indefinitely at a cost of extra resource
* usage. Once the reference count drops to the point where the manager is the
* only reference the messages is recycled using whatever method is implemented
* in the manager.
*
* # endpoint_message_manager:
* An object that manages connection_message_managers. Implements the
* get_message_manager() method. This is used once by each connection to
* request the message manager that they are supposed to use to manage message
* buffers for their own use.
*
* TYPES OF CONNECTION_MESSAGE_MANAGERS
* - allocate a message with the exact size every time one is requested
* - maintain a pool of pre-allocated messages and return one when needed.
* Recycle previously used messages back into the pool
*
* TYPES OF ENDPOINT_MESSAGE_MANAGERS
* - allocate a new connection manager for each connection. Message pools
* become connection specific. This increases memory usage but improves
* concurrency.
* - allocate a single connection manager and share a pointer to it with all
* connections created by this endpoint. The message pool will be shared
* among all connections, improving memory usage and performance at the cost
* of reduced concurrency
*/
/// Represents a buffer for a single WebSocket message.
/**
*
*
*/
template <template<class> class con_msg_manager>
class message {
public:
typedef lib::shared_ptr<message> ptr;
typedef con_msg_manager<message> con_msg_man_type;
typedef typename con_msg_man_type::ptr con_msg_man_ptr;
typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;
/// Construct an empty message
/**
* Construct an empty message
*/
message(const con_msg_man_ptr manager)
: m_manager(manager)
, m_prepared(false)
, m_fin(true)
, m_terminal(false)
, m_compressed(false) {}
/// Construct a message and fill in some values
/**
*
*/
message(const con_msg_man_ptr manager, frame::opcode::value op, size_t size = 128)
: m_manager(manager)
, m_opcode(op)
, m_prepared(false)
, m_fin(true)
, m_terminal(false)
, m_compressed(false)
{
m_payload.reserve(size);
}
/// Return whether or not the message has been prepared for sending
/**
* The prepared flag indicates that the message has been prepared by a
* websocket protocol processor and is ready to be written to the wire.
*
* @return whether or not the message has been prepared for sending
*/
bool get_prepared() const {
return m_prepared;
}
/// Set or clear the flag that indicates that the message has been prepared
/**
* This flag should not be set by end user code without a very good reason.
*
* @param value The value to set the prepared flag to
*/
void set_prepared(bool value) {
m_prepared = value;
}
/// Return whether or not the message is flagged as compressed
/**
* @return whether or not the message is/should be compressed
*/
bool get_compressed() const {
return m_compressed;
}
/// Set or clear the compression flag
/**
* Setting the compression flag indicates that the data in this message
* would benefit from compression. If both endpoints negotiate a compression
* extension WebSocket++ will attempt to compress messages with this flag.
* Setting this flag does not guarantee that the message will be compressed.
*
* @param value The value to set the compressed flag to
*/
void set_compressed(bool value) {
m_compressed = value;
}
/// Get whether or not the message is terminal
/**
* Messages can be flagged as terminal, which results in the connection
* being close after they are written rather than the implementation going
* on to the next message in the queue. This is typically used internally
* for close messages only.
*
* @return Whether or not this message is marked terminal
*/
bool get_terminal() const {
return m_terminal;
}
/// Set the terminal flag
/**
* This flag should not be set by end user code without a very good reason.
*
* @see get_terminal()
*
* @param value The value to set the terminal flag to.
*/
void set_terminal(bool value) {
m_terminal = value;
}
/// Read the fin bit
/**
* A message with the fin bit set will be sent as the last message of its
* sequence. A message with the fin bit cleared will require subsequent
* frames of opcode continuation until one of them has the fin bit set.
*
* The remote end likely will not deliver any bytes until the frame with the fin
* bit set has been received.
*
* @return Whether or not the fin bit is set
*/
bool get_fin() const {
return m_fin;
}
/// Set the fin bit
/**
* @see get_fin for a more detailed explaination of the fin bit
*
* @param value The value to set the fin bit to.
*/
void set_fin(bool value) {
m_fin = value;
}
/// Return the message opcode
frame::opcode::value get_opcode() const {
return m_opcode;
}
/// Set the opcode
void set_opcode(frame::opcode::value op) {
m_opcode = op;
}
/// Return the prepared frame header
/**
* This value is typically set by a websocket protocol processor
* and shouldn't be tampered with.
*/
std::string const & get_header() const {
return m_header;
}
/// Set prepared frame header
/**
* Under normal circumstances this should not be called by end users
*
* @param header A string to set the header to.
*/
void set_header(std::string const & header) {
m_header = header;
}
std::string const & get_extension_data() const {
return m_extension_data;
}
/// Get a reference to the payload string
/**
* @return A const reference to the message's payload string
*/
std::string const & get_payload() const {
return m_payload;
}
/// Get a non-const reference to the payload string
/**
* @return A reference to the message's payload string
*/
std::string & get_raw_payload() {
return m_payload;
}
/// Set payload data
/**
* Set the message buffer's payload to the given value.
*
* @param payload A string to set the payload to.
*/
void set_payload(std::string const & payload) {
m_payload = payload;
}
/// Set payload data
/**
* Set the message buffer's payload to the given value.
*
* @param payload A pointer to a data array to set to.
* @param len The length of new payload in bytes.
*/
void set_payload(void const * payload, size_t len) {
m_payload.reserve(len);
char const * pl = static_cast<char const *>(payload);
m_payload.assign(pl, pl + len);
}
/// Append payload data
/**
* Append data to the message buffer's payload.
*
* @param payload A string containing the data array to append.
*/
void append_payload(std::string const & payload) {
m_payload.append(payload);
}
/// Append payload data
/**
* Append data to the message buffer's payload.
*
* @param payload A pointer to a data array to append
* @param len The length of payload in bytes
*/
void append_payload(void const * payload, size_t len) {
m_payload.reserve(m_payload.size()+len);
m_payload.append(static_cast<char const *>(payload),len);
}
/// Recycle the message
/**
* A request to recycle this message was received. Forward that request to
* the connection message manager for processing. Errors and exceptions
* from the manager's recycle member function should be passed back up the
* call chain. The caller to message::recycle will deal with them.
*
* Recycle must *only* be called by the message shared_ptr's destructor.
* Once recycled successfully, ownership of the memory has been passed to
* another system and must not be accessed again.
*
* @return true if the message was successfully recycled, false otherwise.
*/
bool recycle() {
con_msg_man_ptr shared = m_manager.lock();
if (shared) {
return shared->recycle(this);
} else {
return false;
}
}
private:
con_msg_man_weak_ptr m_manager;
std::string m_header;
std::string m_extension_data;
std::string m_payload;
frame::opcode::value m_opcode;
bool m_prepared;
bool m_fin;
bool m_terminal;
bool m_compressed;
};
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_ALLOC_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP
#include <websocketpp/common/memory.hpp>
#include <string>
namespace websocketpp {
namespace message_buffer {
/* # message:
* object that stores a message while it is being sent or received. Contains
* the message payload itself, the message header, the extension data, and the
* opcode.
*
* # connection_message_manager:
* An object that manages all of the message_buffers associated with a given
* connection. Implements the get_message_buffer(size) method that returns
* a message buffer at least size bytes long.
*
* Message buffers are reference counted with shared ownership semantics. Once
* requested from the manager the requester and it's associated downstream code
* may keep a pointer to the message indefinitely at a cost of extra resource
* usage. Once the reference count drops to the point where the manager is the
* only reference the messages is recycled using whatever method is implemented
* in the manager.
*
* # endpoint_message_manager:
* An object that manages connection_message_managers. Implements the
* get_message_manager() method. This is used once by each connection to
* request the message manager that they are supposed to use to manage message
* buffers for their own use.
*
* TYPES OF CONNECTION_MESSAGE_MANAGERS
* - allocate a message with the exact size every time one is requested
* - maintain a pool of pre-allocated messages and return one when needed.
* Recycle previously used messages back into the pool
*
* TYPES OF ENDPOINT_MESSAGE_MANAGERS
* - allocate a new connection manager for each connection. Message pools
* become connection specific. This increases memory usage but improves
* concurrency.
* - allocate a single connection manager and share a pointer to it with all
* connections created by this endpoint. The message pool will be shared
* among all connections, improving memory usage and performance at the cost
* of reduced concurrency
*/
/// Custom deleter for use in shared_ptrs to message.
/**
* This is used to catch messages about to be deleted and offer the manager the
* ability to recycle them instead. Message::recycle will return true if it was
* successfully recycled and false otherwise. In the case of exceptions or error
* this deleter frees the memory.
*/
template <typename T>
void message_deleter(T* msg) {
try {
if (!msg->recycle()) {
delete msg;
}
} catch (...) {
// TODO: is there a better way to ensure this function doesn't throw?
delete msg;
}
}
/// Represents a buffer for a single WebSocket message.
/**
*
*
*/
template <typename con_msg_manager>
class message {
public:
typedef lib::shared_ptr<message> ptr;
typedef typename con_msg_manager::weak_ptr con_msg_man_ptr;
message(con_msg_man_ptr manager, size_t size = 128)
: m_manager(manager)
, m_payload(size) {}
frame::opcode::value get_opcode() const {
return m_opcode;
}
const std::string& get_header() const {
return m_header;
}
const std::string& get_extension_data() const {
return m_extension_data;
}
const std::string& get_payload() const {
return m_payload;
}
/// Recycle the message
/**
* A request to recycle this message was received. Forward that request to
* the connection message manager for processing. Errors and exceptions
* from the manager's recycle member function should be passed back up the
* call chain. The caller to message::recycle will deal with them.
*
* Recycle must *only* be called by the message shared_ptr's destructor.
* Once recycled successfully, ownership of the memory has been passed to
* another system and must not be accessed again.
*
* @return true if the message was successfully recycled, false otherwise.
*/
bool recycle() {
typename con_msg_manager::ptr shared = m_manager.lock();
if (shared) {
return shared->(recycle(this));
} else {
return false;
}
}
private:
con_msg_man_ptr m_manager;
frame::opcode::value m_opcode;
std::string m_header;
std::string m_extension_data;
std::string m_payload;
};
namespace alloc {
/// A connection message manager that allocates a new message for each
/// request.
template <typename message>
class con_msg_manager {
public:
typedef lib::shared_ptr<con_msg_manager> ptr;
typedef lib::weak_ptr<con_msg_manager> weak_ptr;
typedef typename message::ptr message_ptr;
/// Get a message buffer with specified size
/**
* @param size Minimum size in bytes to request for the message payload.
*
* @return A shared pointer to a new message with specified size.
*/
message_ptr get_message(size_t size) const {
return lib::make_shared<message>(size);
}
/// Recycle a message
/**
* This method shouldn't be called. If it is, return false to indicate an
* error. The rest of the method recycle chain should notice this and free
* the memory.
*
* @param msg The message to be recycled.
*
* @return true if the message was successfully recycled, false otherwse.
*/
bool recycle(message * msg) {
return false;
}
};
/// An endpoint message manager that allocates a new manager for each
/// connection.
template <typename con_msg_manager>
class endpoint_msg_manager {
public:
typedef typename con_msg_manager::ptr con_msg_man_ptr;
/// Get a pointer to a connection message manager
/**
* @return A pointer to the requested connection message manager.
*/
con_msg_man_ptr get_manager() const {
return lib::make_shared<con_msg_manager>();
}
};
} // namespace alloc
namespace pool {
/// A connection messages manager that maintains a pool of messages that is
/// used to fulfill get_message requests.
class con_msg_manager {
};
/// An endpoint manager that maintains a shared pool of connection managers
/// and returns an appropriate one for the requesting connection.
class endpoint_msg_manager {
};
} // namespace pool
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP

View File

@@ -0,0 +1,299 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_BASE_HPP
#define WEBSOCKETPP_PROCESSOR_BASE_HPP
#include <websocketpp/close.hpp>
#include <websocketpp/utilities.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
namespace websocketpp {
namespace processor {
/// Constants related to processing WebSocket connections
namespace constants {
static char const upgrade_token[] = "websocket";
static char const connection_token[] = "Upgrade";
static char const handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
} // namespace constants
/// Processor class related error codes
namespace error_cat {
enum value {
BAD_REQUEST = 0, // Error was the result of improperly formatted user input
INTERNAL_ERROR = 1, // Error was a logic error internal to WebSocket++
PROTOCOL_VIOLATION = 2,
MESSAGE_TOO_BIG = 3,
PAYLOAD_VIOLATION = 4 // Error was due to receiving invalid payload data
};
} // namespace error_cat
/// Error code category and codes used by all processor types
namespace error {
enum processor_errors {
/// Catch-all error for processor policy errors that don't fit in other
/// categories
general = 1,
/// Error was the result of improperly formatted user input
bad_request,
/// Processor encountered a protocol violation in an incoming message
protocol_violation,
/// Processor encountered a message that was too large
message_too_big,
/// Processor encountered invalid payload data.
invalid_payload,
/// The processor method was called with invalid arguments
invalid_arguments,
/// Opcode was invalid for requested operation
invalid_opcode,
/// Control frame too large
control_too_big,
/// Illegal use of reserved bit
invalid_rsv_bit,
/// Fragmented control message
fragmented_control,
/// Continuation without message
invalid_continuation,
/// Clients may not send unmasked frames
masking_required,
/// Servers may not send masked frames
masking_forbidden,
/// Payload length not minimally encoded
non_minimal_encoding,
/// Not supported on 32 bit systems
requires_64bit,
/// Invalid UTF-8 encoding
invalid_utf8,
/// Operation required not implemented functionality
not_implemented,
/// Invalid HTTP method
invalid_http_method,
/// Invalid HTTP version
invalid_http_version,
/// Invalid HTTP status
invalid_http_status,
/// Missing Required Header
missing_required_header,
/// Embedded SHA-1 library error
sha1_library,
/// No support for this feature in this protocol version.
no_protocol_support,
/// Reserved close code used
reserved_close_code,
/// Invalid close code used
invalid_close_code,
/// Using a reason requires a close code
reason_requires_code,
/// Error parsing subprotocols
subprotocol_parse_error,
/// Error parsing extensions
extension_parse_error,
/// Extension related operation was ignored because extensions are disabled
extensions_disabled,
/// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes
/// after the handshake. Less than 8 bytes were read.
short_key3
};
/// Category for processor errors
class processor_category : public lib::error_category {
public:
processor_category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.processor";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic processor error";
case error::bad_request:
return "invalid user input";
case error::protocol_violation:
return "Generic protocol violation";
case error::message_too_big:
return "A message was too large";
case error::invalid_payload:
return "A payload contained invalid data";
case error::invalid_arguments:
return "invalid function arguments";
case error::invalid_opcode:
return "invalid opcode";
case error::control_too_big:
return "Control messages are limited to fewer than 125 characters";
case error::invalid_rsv_bit:
return "Invalid use of reserved bits";
case error::fragmented_control:
return "Control messages cannot be fragmented";
case error::invalid_continuation:
return "Invalid message continuation";
case error::masking_required:
return "Clients may not send unmasked frames";
case error::masking_forbidden:
return "Servers may not send masked frames";
case error::non_minimal_encoding:
return "Payload length was not minimally encoded";
case error::requires_64bit:
return "64 bit frames are not supported on 32 bit systems";
case error::invalid_utf8:
return "Invalid UTF8 encoding";
case error::not_implemented:
return "Operation required not implemented functionality";
case error::invalid_http_method:
return "Invalid HTTP method.";
case error::invalid_http_version:
return "Invalid HTTP version.";
case error::invalid_http_status:
return "Invalid HTTP status.";
case error::missing_required_header:
return "A required HTTP header is missing";
case error::sha1_library:
return "SHA-1 library error";
case error::no_protocol_support:
return "The WebSocket protocol version in use does not support this feature";
case error::reserved_close_code:
return "Reserved close code used";
case error::invalid_close_code:
return "Invalid close code used";
case error::reason_requires_code:
return "Using a close reason requires a valid close code";
case error::subprotocol_parse_error:
return "Error parsing subprotocol header";
case error::extension_parse_error:
return "Error parsing extension header";
case error::extensions_disabled:
return "Extensions are disabled";
case error::short_key3:
return "Short Hybi00 Key 3 read";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the processor error category
inline lib::error_category const & get_processor_category() {
static processor_category instance;
return instance;
}
/// Create an error code with the given value and the processor category
inline lib::error_code make_error_code(error::processor_errors e) {
return lib::error_code(static_cast<int>(e), get_processor_category());
}
/// Converts a processor error_code into a websocket close code
/**
* Looks up the appropriate WebSocket close code that should be sent after an
* error of this sort occurred.
*
* If the error is not in the processor category close::status::blank is
* returned.
*
* If the error isn't normally associated with reasons to close a connection
* (such as errors intended to be used internally or delivered to client
* applications, ex: invalid arguments) then
* close::status::internal_endpoint_error is returned.
*/
inline close::status::value to_ws(lib::error_code ec) {
if (ec.category() != get_processor_category()) {
return close::status::blank;
}
switch (ec.value()) {
case error::protocol_violation:
case error::control_too_big:
case error::invalid_opcode:
case error::invalid_rsv_bit:
case error::fragmented_control:
case error::invalid_continuation:
case error::masking_required:
case error::masking_forbidden:
case error::reserved_close_code:
case error::invalid_close_code:
return close::status::protocol_error;
case error::invalid_payload:
case error::invalid_utf8:
return close::status::invalid_payload;
case error::message_too_big:
return close::status::message_too_big;
default:
return close::status::internal_endpoint_error;
}
}
} // namespace error
} // namespace processor
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::processor::error::processor_errors>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif //WEBSOCKETPP_PROCESSOR_BASE_HPP

View File

@@ -0,0 +1,462 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI00_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP
#include <websocketpp/frame.hpp>
#include <websocketpp/http/constants.hpp>
#include <websocketpp/utf8_validator.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/common/md5.hpp>
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/processors/processor.hpp>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 00
/**
* There are many differences between Hybi 00 and Hybi 13
*/
template <typename config>
class hybi00 : public processor<config> {
public:
typedef processor<config> base;
typedef typename config::request_type request_type;
typedef typename config::response_type response_type;
typedef typename config::message_type message_type;
typedef typename message_type::ptr message_ptr;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
explicit hybi00(bool secure, bool p_is_server, msg_manager_ptr manager)
: processor<config>(secure, p_is_server)
, msg_hdr(0x00)
, msg_ftr(0xff)
, m_state(HEADER)
, m_msg_manager(manager) {}
int get_version() const {
return 0;
}
lib::error_code validate_handshake(request_type const & r) const {
if (r.get_method() != "GET") {
return make_error_code(error::invalid_http_method);
}
if (r.get_version() != "HTTP/1.1") {
return make_error_code(error::invalid_http_version);
}
// required headers
// Host is required by HTTP/1.1
// Connection is required by is_websocket_handshake
// Upgrade is required by is_websocket_handshake
if (r.get_header("Sec-WebSocket-Key1").empty() ||
r.get_header("Sec-WebSocket-Key2").empty() ||
r.get_header("Sec-WebSocket-Key3").empty())
{
return make_error_code(error::missing_required_header);
}
return lib::error_code();
}
lib::error_code process_handshake(request_type const & req,
std::string const & subprotocol, response_type & res) const
{
char key_final[16];
// copy key1 into final key
decode_client_key(req.get_header("Sec-WebSocket-Key1"), &key_final[0]);
// copy key2 into final key
decode_client_key(req.get_header("Sec-WebSocket-Key2"), &key_final[4]);
// copy key3 into final key
// key3 should be exactly 8 bytes. If it is more it will be truncated
// if it is less the final key will almost certainly be wrong.
// TODO: decide if it is best to silently fail here or produce some sort
// of warning or exception.
std::string const & key3 = req.get_header("Sec-WebSocket-Key3");
std::copy(key3.c_str(),
key3.c_str()+(std::min)(static_cast<size_t>(8), key3.size()),
&key_final[8]);
res.append_header(
"Sec-WebSocket-Key3",
md5::md5_hash_string(std::string(key_final,16))
);
res.append_header("Upgrade","WebSocket");
res.append_header("Connection","Upgrade");
// Echo back client's origin unless our local application set a
// more restrictive one.
if (res.get_header("Sec-WebSocket-Origin").empty()) {
res.append_header("Sec-WebSocket-Origin",req.get_header("Origin"));
}
// Echo back the client's request host unless our local application
// set a different one.
if (res.get_header("Sec-WebSocket-Location").empty()) {
uri_ptr uri = get_uri(req);
res.append_header("Sec-WebSocket-Location",uri->str());
}
if (!subprotocol.empty()) {
res.replace_header("Sec-WebSocket-Protocol",subprotocol);
}
return lib::error_code();
}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 00 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
/// Validate the server's response to an outgoing handshake request
/**
* The Hybi 00 processor only implements incoming connections so this will
* always return an error.
*
* @param req The original request sent
* @param res The reponse to generate
* @return An error code, 0 on success, non-zero for other errors
*/
lib::error_code validate_server_handshake_response(request_type const &,
response_type &) const
{
return error::make_error_code(error::no_protocol_support);
}
std::string get_raw(response_type const & res) const {
response_type temp = res;
temp.remove_header("Sec-WebSocket-Key3");
return temp.raw() + res.get_header("Sec-WebSocket-Key3");
}
std::string const & get_origin(request_type const & r) const {
return r.get_header("Origin");
}
/// Extracts requested subprotocols from a handshake request
/**
* hybi00 does support subprotocols
* https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-1.9
*
* @param [in] req The request to extract from
* @param [out] subprotocol_list A reference to a vector of strings to store
* the results in.
*/
lib::error_code extract_subprotocols(request_type const & req,
std::vector<std::string> & subprotocol_list)
{
if (!req.get_header("Sec-WebSocket-Protocol").empty()) {
http::parameter_list p;
if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) {
http::parameter_list::const_iterator it;
for (it = p.begin(); it != p.end(); ++it) {
subprotocol_list.push_back(it->first);
}
} else {
return error::make_error_code(error::subprotocol_parse_error);
}
}
return lib::error_code();
}
uri_ptr get_uri(request_type const & request) const {
std::string h = request.get_header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return lib::make_shared<uri>(base::m_secure, h, request.get_uri());
} else {
return lib::make_shared<uri>(base::m_secure,
h.substr(0,last_colon),
h.substr(last_colon+1),
request.get_uri());
}
// TODO: check if get_uri is a full uri
}
/// Get hybi00 handshake key3
/**
* @todo This doesn't appear to be used anymore. It might be able to be
* removed
*/
std::string get_key3() const {
return "";
}
/// Process new websocket connection bytes
size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {
// if in state header we are expecting a 0x00 byte, if we don't get one
// it is a fatal error
size_t p = 0; // bytes processed
size_t l = 0;
ec = lib::error_code();
while (p < len) {
if (m_state == HEADER) {
if (buf[p] == msg_hdr) {
p++;
m_msg_ptr = m_msg_manager->get_message(frame::opcode::text,1);
if (!m_msg_ptr) {
ec = make_error_code(websocketpp::error::no_incoming_buffers);
m_state = FATAL_ERROR;
} else {
m_state = PAYLOAD;
}
} else {
ec = make_error_code(error::protocol_violation);
m_state = FATAL_ERROR;
}
} else if (m_state == PAYLOAD) {
uint8_t *it = std::find(buf+p,buf+len,msg_ftr);
// 0 1 2 3 4 5
// 0x00 0x23 0x23 0x23 0xff 0xXX
// Copy payload bytes into message
l = static_cast<size_t>(it-(buf+p));
m_msg_ptr->append_payload(buf+p,l);
p += l;
if (it != buf+len) {
// message is done, copy it and the trailing
p++;
// TODO: validation
m_state = READY;
}
} else {
// TODO
break;
}
}
// If we get one, we create a new message and move to application state
// if in state application we are copying bytes into the output message
// and validating them for UTF8 until we hit a 0xff byte. Once we hit
// 0x00, the message is complete and is dispatched. Then we go back to
// header state.
//ec = make_error_code(error::not_implemented);
return p;
}
bool ready() const {
return (m_state == READY);
}
bool get_error() const {
return false;
}
message_ptr get_message() {
message_ptr ret = m_msg_ptr;
m_msg_ptr = message_ptr();
m_state = HEADER;
return ret;
}
/// Prepare a message for writing
/**
* Performs validation, masking, compression, etc. will return an error if
* there was an error, otherwise msg will be ready to be written
*/
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
{
if (!in || !out) {
return make_error_code(error::invalid_arguments);
}
// TODO: check if the message is prepared already
// validate opcode
if (in->get_opcode() != frame::opcode::text) {
return make_error_code(error::invalid_opcode);
}
std::string& i = in->get_raw_payload();
//std::string& o = out->get_raw_payload();
// validate payload utf8
if (!utf8_validator::validate(i)) {
return make_error_code(error::invalid_payload);
}
// generate header
out->set_header(std::string(reinterpret_cast<char const *>(&msg_hdr),1));
// process payload
out->set_payload(i);
out->append_payload(std::string(reinterpret_cast<char const *>(&msg_ftr),1));
// hybi00 doesn't support compression
// hybi00 doesn't have masking
out->set_prepared(true);
return lib::error_code();
}
/// Prepare a ping frame
/**
* Hybi 00 doesn't support pings so this will always return an error
*
* @param in The string to use for the ping payload
* @param out The message buffer to prepare the ping in.
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_ping(std::string const &, message_ptr) const
{
return lib::error_code(error::no_protocol_support);
}
/// Prepare a pong frame
/**
* Hybi 00 doesn't support pongs so this will always return an error
*
* @param in The string to use for the pong payload
* @param out The message buffer to prepare the pong in.
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_pong(std::string const &, message_ptr) const
{
return lib::error_code(error::no_protocol_support);
}
/// Prepare a close frame
/**
* Hybi 00 doesn't support the close code or reason so these parameters are
* ignored.
*
* @param code The close code to send
* @param reason The reason string to send
* @param out The message buffer to prepare the fame in
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_close(close::status::value, std::string const &,
message_ptr out) const
{
if (!out) {
return lib::error_code(error::invalid_arguments);
}
std::string val;
val.append(1,'\xff');
val.append(1,'\x00');
out->set_payload(val);
out->set_prepared(true);
return lib::error_code();
}
private:
void decode_client_key(std::string const & key, char * result) const {
unsigned int spaces = 0;
std::string digits;
uint32_t num;
// key2
for (size_t i = 0; i < key.size(); i++) {
if (key[i] == ' ') {
spaces++;
} else if (key[i] >= '0' && key[i] <= '9') {
digits += key[i];
}
}
num = static_cast<uint32_t>(strtoul(digits.c_str(), NULL, 10));
if (spaces > 0 && num > 0) {
num = htonl(num/spaces);
std::copy(reinterpret_cast<char*>(&num),
reinterpret_cast<char*>(&num)+4,
result);
} else {
std::fill(result,result+4,0);
}
}
enum state {
HEADER = 0,
PAYLOAD = 1,
READY = 2,
FATAL_ERROR = 3
};
uint8_t const msg_hdr;
uint8_t const msg_ftr;
state m_state;
msg_manager_ptr m_msg_manager;
message_ptr m_msg_ptr;
utf8_validator::validator m_validator;
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI00_HPP

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI07_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI07_HPP
#include <websocketpp/processors/hybi08.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 07
/**
* The primary difference between 07 and 08 is a version number.
*/
template <typename config>
class hybi07 : public hybi08<config> {
public:
typedef typename config::request_type request_type;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
typedef typename config::rng_type rng_type;
explicit hybi07(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
: hybi08<config>(secure, p_is_server, manager, rng) {}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 07 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
int get_version() const {
return 7;
}
private:
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI07_HPP

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI08_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI08_HPP
#include <websocketpp/processors/hybi13.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 08
/**
* The primary difference between 08 and 13 is a different origin header name
*/
template <typename config>
class hybi08 : public hybi13<config> {
public:
typedef hybi08<config> type;
typedef typename config::request_type request_type;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
typedef typename config::rng_type rng_type;
explicit hybi08(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
: hybi13<config>(secure, p_is_server, manager, rng) {}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 08 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
int get_version() const {
return 8;
}
std::string const & get_origin(request_type const & r) const {
return r.get_header("Sec-WebSocket-Origin");
}
private:
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI08_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2015, 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_PROCESSOR_HPP
#define WEBSOCKETPP_PROCESSOR_HPP
#include <websocketpp/processors/base.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/close.hpp>
#include <websocketpp/utilities.hpp>
#include <websocketpp/uri.hpp>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
namespace websocketpp {
/// Processors encapsulate the protocol rules specific to each WebSocket version
/**
* The processors namespace includes a number of free functions that operate on
* various WebSocket related data structures and perform processing that is not
* related to specific versions of the protocol.
*
* It also includes the abstract interface for the protocol specific processing
* engines. These engines wrap all of the logic necessary for parsing and
* validating WebSocket handshakes and messages of specific protocol version
* and set of allowed extensions.
*
* An instance of a processor represents the state of a single WebSocket
* connection of the associated version. One processor instance is needed per
* logical WebSocket connection.
*/
namespace processor {
/// Determine whether or not a generic HTTP request is a WebSocket handshake
/**
* @param r The HTTP request to read.
*
* @return True if the request is a WebSocket handshake, false otherwise
*/
template <typename request_type>
bool is_websocket_handshake(request_type& r) {
using utility::ci_find_substr;
std::string const & upgrade_header = r.get_header("Upgrade");
if (ci_find_substr(upgrade_header, constants::upgrade_token,
sizeof(constants::upgrade_token)-1) == upgrade_header.end())
{
return false;
}
std::string const & con_header = r.get_header("Connection");
if (ci_find_substr(con_header, constants::connection_token,
sizeof(constants::connection_token)-1) == con_header.end())
{
return false;
}
return true;
}
/// Extract the version from a WebSocket handshake request
/**
* A blank version header indicates a spec before versions were introduced.
* The only such versions in shipping products are Hixie Draft 75 and Hixie
* Draft 76. Draft 75 is present in Chrome 4-5 and Safari 5.0.0, Draft 76 (also
* known as hybi 00 is present in Chrome 6-13 and Safari 5.0.1+. As
* differentiating between these two sets of browsers is very difficult and
* Safari 5.0.1+ accounts for the vast majority of cases in the wild this
* function assumes that all handshakes without a valid version header are
* Hybi 00.
*
* @param r The WebSocket handshake request to read.
*
* @return The WebSocket handshake version or -1 if there was an extraction
* error.
*/
template <typename request_type>
int get_websocket_version(request_type& r) {
if (!r.ready()) {
return -2;
}
if (r.get_header("Sec-WebSocket-Version").empty()) {
return 0;
}
int version;
std::istringstream ss(r.get_header("Sec-WebSocket-Version"));
if ((ss >> version).fail()) {
return -1;
}
return version;
}
/// Extract a URI ptr from the host header of the request
/**
* @param request The request to extract the Host header from.
*
* @param scheme The scheme under which this request was received (ws, wss,
* http, https, etc)
*
* @return A uri_pointer that encodes the value of the host header.
*/
template <typename request_type>
uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
std::string h = request.get_header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return lib::make_shared<uri>(scheme, h, request.get_uri());
} else {
return lib::make_shared<uri>(scheme,
h.substr(0,last_colon),
h.substr(last_colon+1),
request.get_uri());
}
}
/// WebSocket protocol processor abstract base class
template <typename config>
class processor {
public:
typedef processor<config> type;
typedef typename config::request_type request_type;
typedef typename config::response_type response_type;
typedef typename config::message_type::ptr message_ptr;
typedef std::pair<lib::error_code,std::string> err_str_pair;
explicit processor(bool secure, bool p_is_server)
: m_secure(secure)
, m_server(p_is_server)
, m_max_message_size(config::max_message_size)
{}
virtual ~processor() {}
/// Get the protocol version of this processor
virtual int get_version() const = 0;
/// Get maximum message size
/**
* Get maximum message size. Maximum message size determines the point at which the
* processor will fail a connection with the message_too_big protocol error.
*
* The default is retrieved from the max_message_size value from the template config
*
* @since 0.3.0
*/
size_t get_max_message_size() const {
return m_max_message_size;
}
/// Set maximum message size
/**
* Set maximum message size. Maximum message size determines the point at which the
* processor will fail a connection with the message_too_big protocol error.
*
* The default is retrieved from the max_message_size value from the template config
*
* @since 0.3.0
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_message_size(size_t new_value) {
m_max_message_size = new_value;
}
/// Returns whether or not the permessage_compress extension is implemented
/**
* Compile time flag that indicates whether this processor has implemented
* the permessage_compress extension. By default this is false.
*/
virtual bool has_permessage_compress() const {
return false;
}
/// Initializes extensions based on the Sec-WebSocket-Extensions header
/**
* Reads the Sec-WebSocket-Extensions header and determines if any of the
* requested extensions are supported by this processor. If they are their
* settings data is initialized and an extension string to send to the
* is returned.
*
* @param request The request or response headers to look at.
*/
virtual err_str_pair negotiate_extensions(request_type const &) {
return err_str_pair();
}
/// Initializes extensions based on the Sec-WebSocket-Extensions header
/**
* Reads the Sec-WebSocket-Extensions header and determines if any of the
* requested extensions were accepted by the server. If they are their
* settings data is initialized. If they are not a list of required
* extensions (if any) is returned. This list may be sent back to the server
* as a part of the 1010/Extension required close code.
*
* @param response The request or response headers to look at.
*/
virtual err_str_pair negotiate_extensions(response_type const &) {
return err_str_pair();
}
/// validate a WebSocket handshake request for this version
/**
* @param request The WebSocket handshake request to validate.
* is_websocket_handshake(request) must be true and
* get_websocket_version(request) must equal this->get_version().
*
* @return A status code, 0 on success, non-zero for specific sorts of
* failure
*/
virtual lib::error_code validate_handshake(request_type const & request) const = 0;
/// Calculate the appropriate response for this websocket request
/**
* @param req The request to process
*
* @param subprotocol The subprotocol in use
*
* @param res The response to store the processed response in
*
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code process_handshake(request_type const & req,
std::string const & subprotocol, response_type& res) const = 0;
/// Fill in an HTTP request for an outgoing connection handshake
/**
* @param req The request to process.
*
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code client_handshake_request(request_type & req,
uri_ptr uri, std::vector<std::string> const & subprotocols) const = 0;
/// Validate the server's response to an outgoing handshake request
/**
* @param req The original request sent
* @param res The reponse to generate
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code validate_server_handshake_response(request_type
const & req, response_type & res) const = 0;
/// Given a completed response, get the raw bytes to put on the wire
virtual std::string get_raw(response_type const & request) const = 0;
/// Return the value of the header containing the CORS origin.
virtual std::string const & get_origin(request_type const & request) const = 0;
/// Extracts requested subprotocols from a handshake request
/**
* Extracts a list of all subprotocols that the client has requested in the
* given opening handshake request.
*
* @param [in] req The request to extract from
* @param [out] subprotocol_list A reference to a vector of strings to store
* the results in.
*/
virtual lib::error_code extract_subprotocols(const request_type & req,
std::vector<std::string> & subprotocol_list) = 0;
/// Extracts client uri from a handshake request
virtual uri_ptr get_uri(request_type const & request) const = 0;
/// process new websocket connection bytes
/**
* WebSocket connections are a continous stream of bytes that must be
* interpreted by a protocol processor into discrete frames.
*
* @param buf Buffer from which bytes should be read.
* @param len Length of buffer
* @param ec Reference to an error code to return any errors in
* @return Number of bytes processed
*/
virtual size_t consume(uint8_t *buf, size_t len, lib::error_code & ec) = 0;
/// Checks if there is a message ready
/**
* Checks if the most recent consume operation processed enough bytes to
* complete a new WebSocket message. The message can be retrieved by calling
* get_message() which will reset the internal state to not-ready and allow
* consume to read more bytes.
*
* @return Whether or not a message is ready.
*/
virtual bool ready() const = 0;
/// Retrieves the most recently processed message
/**
* Retrieves a shared pointer to the recently completed message if there is
* one. If ready() returns true then there is a message available.
* Retrieving the message with get_message will reset the state of ready.
* As such, each new message may be retrieved only once. Calling get_message
* when there is no message available will result in a null pointer being
* returned.
*
* @return A pointer to the most recently processed message or a null shared
* pointer.
*/
virtual message_ptr get_message() = 0;
/// Tests whether the processor is in a fatal error state
virtual bool get_error() const = 0;
/// Retrieves the number of bytes presently needed by the processor
/// This value may be used as a hint to the transport layer as to how many
/// bytes to wait for before running consume again.
virtual size_t get_bytes_needed() const {
return 1;
}
/// Prepare a data message for writing
/**
* Performs validation, masking, compression, etc. will return an error if
* there was an error, otherwise msg will be ready to be written
*/
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) = 0;
/// Prepare a ping frame
/**
* Ping preparation is entirely state free. There is no payload validation
* other than length. Payload need not be UTF-8.
*
* @param in The string to use for the ping payload
* @param out The message buffer to prepare the ping in.
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_ping(std::string const & in, message_ptr out) const
= 0;
/// Prepare a pong frame
/**
* Pong preparation is entirely state free. There is no payload validation
* other than length. Payload need not be UTF-8.
*
* @param in The string to use for the pong payload
* @param out The message buffer to prepare the pong in.
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_pong(std::string const & in, message_ptr out) const
= 0;
/// Prepare a close frame
/**
* Close preparation is entirely state free. The code and reason are both
* subject to validation. Reason must be valid UTF-8. Code must be a valid
* un-reserved WebSocket close code. Use close::status::no_status to
* indicate no code. If no code is supplied a reason may not be specified.
*
* @param code The close code to send
* @param reason The reason string to send
* @param out The message buffer to prepare the fame in
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_close(close::status::value code,
std::string const & reason, message_ptr out) const = 0;
protected:
bool const m_secure;
bool const m_server;
size_t m_max_message_size;
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HPP

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2014, 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_RANDOM_NONE_HPP
#define WEBSOCKETPP_RANDOM_NONE_HPP
namespace websocketpp {
/// Random number generation policies
namespace random {
/// Stub RNG policy that always returns 0
namespace none {
/// Thread safe stub "random" integer generator.
/**
* This template class provides a random integer stub. The interface mimics the
* WebSocket++ RNG generator classes but the generater function always returns
* zero. This can be used to stub out the RNG for unit and performance testing.
*
* Call operator() to generate the next number
*/
template <typename int_type>
class int_generator {
public:
int_generator() {}
/// advances the engine's state and returns the generated value
int_type operator()() {
return 0;
}
};
} // namespace none
} // namespace random
} // namespace websocketpp
#endif //WEBSOCKETPP_RANDOM_NONE_HPP

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, 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_RANDOM_RANDOM_DEVICE_HPP
#define WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP
#include <websocketpp/common/random.hpp>
namespace websocketpp {
namespace random {
/// RNG policy based on std::random_device or boost::random_device
namespace random_device {
/// Thread safe non-deterministic random integer generator.
/**
* This template class provides thread safe non-deterministic random integer
* generation. Numbers are produced in a uniformly distributed range from the
* smallest to largest value that int_type can store.
*
* Thread-safety is provided via locking based on the concurrency template
* parameter.
*
* Non-deterministic RNG is provided via websocketpp::lib which uses either
* C++11 or Boost 1.47+'s random_device class.
*
* Call operator() to generate the next number
*/
template <typename int_type, typename concurrency>
class int_generator {
public:
typedef typename concurrency::scoped_lock_type scoped_lock_type;
typedef typename concurrency::mutex_type mutex_type;
/// constructor
//mac TODO: figure out if signed types present a range problem
int_generator() {}
/// advances the engine's state and returns the generated value
int_type operator()() {
scoped_lock_type guard(m_lock);
return m_dis(m_rng);
}
private:
lib::random_device m_rng;
lib::uniform_int_distribution<int_type> m_dis;
mutex_type m_lock;
};
} // namespace random_device
} // namespace random
} // namespace websocketpp
#endif //WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP

View File

@@ -0,0 +1,173 @@
/*
* Copyright (c) 2014, 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_CLIENT_ENDPOINT_HPP
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
#include <websocketpp/endpoint.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
namespace websocketpp {
/// Client endpoint role based on the given config
/**
*
*/
template <typename config>
class client : public endpoint<connection<config>,config> {
public:
/// Type of this endpoint
typedef client<config> type;
/// Type of the endpoint concurrency component
typedef typename config::concurrency_type concurrency_type;
/// Type of the endpoint transport component
typedef typename config::transport_type transport_type;
/// Type of the connections this server will create
typedef connection<config> connection_type;
/// Type of a shared pointer to the connections this server will create
typedef typename connection_type::ptr connection_ptr;
/// Type of the connection transport component
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of the endpoint component of this server
typedef endpoint<connection_type,config> endpoint_type;
friend class connection<config>;
explicit client() : endpoint_type(false)
{
endpoint_type::m_alog->write(log::alevel::devel, "client constructor");
}
/// Get a new connection
/**
* Creates and returns a pointer to a new connection to the given URI
* suitable for passing to connect(connection_ptr). This method allows
* applying connection specific settings before performing the opening
* 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
*/
connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {
if (location->get_secure() && !transport_type::is_secure()) {
ec = error::make_error_code(error::endpoint_not_secure);
return connection_ptr();
}
connection_ptr con = endpoint_type::create_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return con;
}
con->set_uri(location);
ec = lib::error_code();
return con;
}
/// Get a new connection (string version)
/**
* Creates and returns a pointer to a new connection to the given URI
* suitable for passing to connect(connection_ptr). This overload allows
* 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
*/
connection_ptr get_connection(std::string const & u, lib::error_code & ec) {
uri_ptr location = lib::make_shared<uri>(u);
if (!location->get_valid()) {
ec = error::make_error_code(error::invalid_uri);
return connection_ptr();
}
return get_connection(location, ec);
}
/// Begin the connection process for the given connection
/**
* Initiates the opening connection handshake for connection con. Exact
* behavior depends on the underlying transport policy.
*
* @param con The connection to connect
*
* @return The pointer to the connection originally passed in.
*/
connection_ptr connect(connection_ptr con) {
// Ask transport to perform a connection
transport_type::async_connect(
lib::static_pointer_cast<transport_con_type>(con),
con->get_uri(),
lib::bind(
&type::handle_connect,
this,
con,
lib::placeholders::_1
)
);
return con;
}
private:
// handle_connect
void handle_connect(connection_ptr con, lib::error_code const & ec) {
if (ec) {
con->terminate(ec);
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_connect error: "+ec.message());
} else {
endpoint_type::m_alog->write(log::alevel::connect,
"Successful connection");
con->start();
}
}
};
} // namespace websocketpp
#endif //WEBSOCKETPP_CLIENT_ENDPOINT_HPP

View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 2014, 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_SERVER_ENDPOINT_HPP
#define WEBSOCKETPP_SERVER_ENDPOINT_HPP
#include <websocketpp/endpoint.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/system_error.hpp>
namespace websocketpp {
/// Server endpoint role based on the given config
/**
*
*/
template <typename config>
class server : public endpoint<connection<config>,config> {
public:
/// Type of this endpoint
typedef server<config> type;
/// Type of the endpoint concurrency component
typedef typename config::concurrency_type concurrency_type;
/// Type of the endpoint transport component
typedef typename config::transport_type transport_type;
/// Type of the connections this server will create
typedef connection<config> connection_type;
/// Type of a shared pointer to the connections this server will create
typedef typename connection_type::ptr connection_ptr;
/// Type of the connection transport component
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of the endpoint component of this server
typedef endpoint<connection_type,config> endpoint_type;
friend class connection<config>;
explicit server() : endpoint_type(true)
{
endpoint_type::m_alog->write(log::alevel::devel, "server constructor");
}
/// Destructor
~server<config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
server<config>(server<config> &) = delete;
// no copy assignment operator because endpoints are not copyable
server<config> & operator=(server<config> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
server<config> & operator=(server<config> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Create and initialize a new connection
/**
* The connection will be initialized and ready to begin. Call its start()
* method to begin the processing loop.
*
* Note: The connection must either be started or terminated using
* connection::terminate in order to avoid memory leaks.
*
* @return A pointer to the new connection.
*/
connection_ptr get_connection() {
return endpoint_type::create_connection();
}
/// Starts the server's async connection acceptance loop (exception free)
/**
* Initiates the server connection acceptance loop. Must be called after
* listen. This method will have no effect until the underlying io_service
* starts running. It may be called after the io_service is already running.
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*
* @param [out] ec A status code indicating an error, if any.
*/
void start_accept(lib::error_code & ec) {
if (!transport_type::is_listening()) {
ec = error::make_error_code(error::async_accept_not_listening);
return;
}
ec = lib::error_code();
connection_ptr con = get_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return;
}
transport_type::async_accept(
lib::static_pointer_cast<transport_con_type>(con),
lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),
ec
);
if (ec && con) {
// If the connection was constructed but the accept failed,
// terminate the connection to prevent memory leaks
con->terminate(lib::error_code());
}
}
/// Starts the server's async connection acceptance loop
/**
* Initiates the server connection acceptance loop. Must be called after
* listen. This method will have no effect until the underlying io_service
* starts running. It may be called after the io_service is already running.
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*/
void start_accept() {
lib::error_code ec;
start_accept(ec);
if (ec) {
throw exception(ec);
}
}
/// Handler callback for start_accept
void handle_accept(connection_ptr con, lib::error_code const & ec) {
if (ec) {
con->terminate(ec);
if (ec == error::operation_canceled) {
endpoint_type::m_elog->write(log::elevel::info,
"handle_accept error: "+ec.message());
} else {
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_accept error: "+ec.message());
}
} else {
con->start();
}
lib::error_code start_ec;
start_accept(start_ec);
if (start_ec == error::async_accept_not_listening) {
endpoint_type::m_elog->write(log::elevel::info,
"Stopping acceptance of new connections because the underlying transport is no longer listening.");
} else if (start_ec) {
endpoint_type::m_elog->write(log::elevel::rerror,
"Restarting async_accept loop failed: "+ec.message());
}
}
};
} // namespace websocketpp
#endif //WEBSOCKETPP_SERVER_ENDPOINT_HPP

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2014, 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_SERVER_HPP
#define WEBSOCKETPP_SERVER_HPP
#include <websocketpp/roles/server_endpoint.hpp>
#endif //WEBSOCKETPP_SERVER_HPP

View File

@@ -0,0 +1,189 @@
/*
*****
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1
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.
*/
#ifndef SHA1_DEFINED
#define SHA1_DEFINED
namespace websocketpp {
namespace sha1 {
namespace { // local
// Rotate an integer value to left.
inline unsigned int rol(unsigned int value, 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;
}
}
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
/// Calculate a SHA1 hash
/**
* @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.
*/
inline void calc(void const * src, size_t 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.
unsigned char const * sarray = (unsigned char const *) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
size_t endCurrentBlock;
size_t currentBlock = 0;
if (bytelength >= 64) {
size_t const endOfFullBlocks = bytelength - 64;
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);
size_t 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;
}
}
} // namespace sha1
} // namespace websocketpp
#endif // SHA1_DEFINED

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 2015, 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_TRANSPORT_ASIO_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/type_traits.hpp>
#include <string>
namespace websocketpp {
namespace transport {
/// Transport policy that uses asio
/**
* This policy uses a single asio io_service to provide transport
* services to a WebSocket++ endpoint.
*/
namespace asio {
// Class to manage the memory to be used for handler-based custom allocation.
// It contains a single block of memory which may be returned for allocation
// requests. If the memory is in use when an allocation request is made, the
// allocator delegates allocation to the global heap.
class handler_allocator {
public:
static const size_t size = 1024;
handler_allocator() : m_in_use(false) {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
handler_allocator(handler_allocator const & cpy) = delete;
handler_allocator & operator =(handler_allocator const &) = delete;
#endif
void * allocate(std::size_t memsize) {
if (!m_in_use && memsize < size) {
m_in_use = true;
return static_cast<void*>(&m_storage);
} else {
return ::operator new(memsize);
}
}
void deallocate(void * pointer) {
if (pointer == &m_storage) {
m_in_use = false;
} else {
::operator delete(pointer);
}
}
private:
// Storage space used for handler-based custom memory allocation.
lib::aligned_storage<size>::type m_storage;
// Whether the handler-based custom allocation storage has been used.
bool m_in_use;
};
// Wrapper class template for handler objects to allow handler memory
// allocation to be customised. Calls to operator() are forwarded to the
// encapsulated handler.
template <typename Handler>
class custom_alloc_handler {
public:
custom_alloc_handler(handler_allocator& a, Handler h)
: allocator_(a),
handler_(h)
{}
template <typename Arg1>
void operator()(Arg1 arg1) {
handler_(arg1);
}
template <typename Arg1, typename Arg2>
void operator()(Arg1 arg1, Arg2 arg2) {
handler_(arg1, arg2);
}
friend void* asio_handler_allocate(std::size_t size,
custom_alloc_handler<Handler> * this_handler)
{
return this_handler->allocator_.allocate(size);
}
friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
custom_alloc_handler<Handler> * this_handler)
{
this_handler->allocator_.deallocate(pointer);
}
private:
handler_allocator & allocator_;
Handler handler_;
};
// Helper function to wrap a handler object to add custom allocation.
template <typename Handler>
inline custom_alloc_handler<Handler> make_custom_alloc_handler(
handler_allocator & a, Handler h)
{
return custom_alloc_handler<Handler>(a, h);
}
// Forward declaration of class endpoint so that it can be friended/referenced
// before being included.
template <typename config>
class endpoint;
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_read_handler;
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_write_handler;
typedef lib::function<void (lib::error_code const & ec)> pre_init_handler;
// handle_timer: dynamic parameters, multiple copies
// handle_proxy_write
// handle_proxy_read
// handle_async_write
// handle_pre_init
/// Asio transport errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// async_read_at_least call requested more bytes than buffer can store
invalid_num_bytes,
/// there was an error in the underlying transport library
pass_through,
/// The connection to the requested proxy server failed
proxy_failed,
/// Invalid Proxy URI
proxy_invalid,
/// Invalid host or service
invalid_host_service
};
/// Asio transport error category
class category : public lib::error_category {
public:
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.asio";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic asio transport policy error";
case error::invalid_num_bytes:
return "async_read_at_least call requested more bytes than buffer can store";
case error::pass_through:
return "Underlying Transport Error";
case error::proxy_failed:
return "Proxy connection failed";
case error::proxy_invalid:
return "Invalid proxy URI";
case error::invalid_host_service:
return "Invalid host or service";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the asio transport error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Create an error code with the given value and the asio transport category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace asio
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::asio::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More