diff --git a/config/config.ini b/config/config.ini index e758918..68cd2fe 100644 --- a/config/config.ini +++ b/config/config.ini @@ -1,6 +1,6 @@ [signal server] ip = localhost -port = 9095 +port = 9090 [stun server] ip = 120.77.216.215 diff --git a/src/ice/ice_agent.cpp b/src/ice/ice_agent.cpp index eace4ee..8562d2b 100644 --- a/src/ice/ice_agent.cpp +++ b/src/ice/ice_agent.cpp @@ -1,127 +1,127 @@ -#include "ice_agent.h" - -#include - -#include - -#include "log.h" - -IceAgent::IceAgent(std::string &ip, uint16_t port) : ip_(ip), port_(port) {} - -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)); - - LOG_INFO("stun server ip[{}] port[{}]", ip_, port_); - - // STUN server example - config.stun_server_host = ip_.c_str(); - config.stun_server_port = port_; - - 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_); - LOG_INFO("Generate 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", (void *)this); - 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; +#include "ice_agent.h" + +#include + +#include + +#include "log.h" + +IceAgent::IceAgent(std::string &ip, uint16_t port) : ip_(ip), port_(port) {} + +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)); + + LOG_INFO("stun server ip[{}] port[{}]", ip_, port_); + + // STUN server example + config.stun_server_host = ip_.c_str(); + config.stun_server_port = port_; + + 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_); + LOG_INFO("Generate local sdp"); + + return local_sdp_; +} + +int IceAgent::SetRemoteSdp(const char *remote_sdp) { + LOG_INFO("[{}] Set remote sdp", (void *)this); + juice_set_remote_description(agent_, remote_sdp); + // LOG_INFO("Remote description:[\n{}]", remote_sdp); + + return 0; +} + +int IceAgent::GatherCandidates() { + LOG_INFO("[{}] Gather candidates", (void *)this); + 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; } \ No newline at end of file diff --git a/src/ice/ice_agent.h b/src/ice/ice_agent.h index cf00a88..50989f8 100644 --- a/src/ice/ice_agent.h +++ b/src/ice/ice_agent.h @@ -1,46 +1,46 @@ -#ifndef _ICE_AGENT_H_ -#define _ICE_AGENT_H_ - -#include - -#include "juice/juice.h" - -class IceAgent { - public: - IceAgent(std::string& ip, uint16_t port); - ~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: - std::string ip_ = ""; - uint16_t port_ = 0; - juice_agent_t* agent_ = nullptr; - char local_sdp_[JUICE_MAX_SDP_STRING_LEN]; - juice_state_t state_; -}; - +#ifndef _ICE_AGENT_H_ +#define _ICE_AGENT_H_ + +#include + +#include "juice/juice.h" + +class IceAgent { + public: + IceAgent(std::string& ip, uint16_t port); + ~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: + std::string ip_ = ""; + uint16_t port_ = 0; + juice_agent_t* agent_ = nullptr; + char local_sdp_[JUICE_MAX_SDP_STRING_LEN]; + juice_state_t state_; +}; + #endif \ No newline at end of file diff --git a/src/ice/ice_transmission.cpp b/src/ice/ice_transmission.cpp index ea6c333..df8a1e1 100644 --- a/src/ice/ice_transmission.cpp +++ b/src/ice/ice_transmission.cpp @@ -15,9 +15,11 @@ const std::vector ice_status = { "JUICE_STATE_COMPLETED", "JUICE_STATE_FAILED"}; IceTransmission::IceTransmission( - bool offer_peer, WsTransmission *ice_ws_transmission, + bool offer_peer, std::string remote_ice_username, + WsTransmission *ice_ws_transmission, std::function on_receive_ice_msg) : offer_peer_(offer_peer), + remote_ice_username_(remote_ice_username), ice_ws_transport_(ice_ws_transmission), on_receive_ice_msg_cb_(on_receive_ice_msg) {} @@ -45,6 +47,7 @@ int IceTransmission::InitIceTransmission(std::string &ip, int port) { if (ice_transmission_obj->offer_peer_) { ice_transmission_obj->GetLocalSdp(); ice_transmission_obj->SendOffer(); + LOG_INFO("[{}] SendOffer", (void *)ice_transmission_obj) } else { ice_transmission_obj->CreateAnswer(); ice_transmission_obj->SendAnswer(); @@ -90,10 +93,18 @@ int IceTransmission::CreateTransmission(const std::string &transmission_id) { return 0; } -int IceTransmission::JoinTransmission(const std::string &transmission_id) { +int IceTransmission::SetTransmissionId(const std::string &transmission_id) { + transmission_id_ = transmission_id; + + return 0; +} + +int IceTransmission::JoinTransmission(const std::string &transmission_id, + const std::string &user_id) { LOG_INFO("Join transport"); offer_peer_ = true; transmission_id_ = transmission_id; + user_id_ = user_id; // if (SignalStatus::Connected != signal_status_) { // LOG_ERROR("Not connect to signalserver"); @@ -112,6 +123,7 @@ int IceTransmission::GatherCandidates() { int IceTransmission::GetLocalSdp() { local_sdp_ = ice_agent_->GenerateLocalSdp(); + LOG_INFO("Local ice username: [{}]", GetIceUsername(local_sdp_)); return 0; } @@ -127,7 +139,7 @@ int IceTransmission::AddRemoteCandidate(const std::string &remote_candidate) { } int IceTransmission::CreateOffer() { - LOG_INFO("Create offer"); + LOG_INFO("[{}] Create offer", (void *)this); GatherCandidates(); return 0; } @@ -135,6 +147,8 @@ int IceTransmission::CreateOffer() { int IceTransmission::SendOffer() { json message = {{"type", "offer"}, {"transmission_id", transmission_id_}, + {"user_id", user_id_}, + {"remote_peer", remote_ice_username_}, {"sdp", local_sdp_}}; // LOG_INFO("Send offer:\n{}", message.dump().c_str()); LOG_INFO("Send offer"); @@ -166,7 +180,7 @@ int IceTransmission::SendAnswer() { {"transmission_id", transmission_id_}, {"sdp", local_sdp_}, {"guest", remote_ice_username_}}; - // LOG_INFO("Send answer:\n{}", message.dump().c_str()); + LOG_INFO("[{}] Send answer to [{}]", GetIceUsername(local_sdp_), remote_ice_username_); diff --git a/src/ice/ice_transmission.h b/src/ice/ice_transmission.h index a24224f..f518e2b 100644 --- a/src/ice/ice_transmission.h +++ b/src/ice/ice_transmission.h @@ -8,7 +8,8 @@ class IceTransmission { public: - IceTransmission(bool offer_peer, WsTransmission *ice_ws_transmission, + IceTransmission(bool offer_peer, std::string remote_ice_username, + WsTransmission *ice_ws_transmission, std::function on_receive_ice_msg); ~IceTransmission(); @@ -18,7 +19,10 @@ class IceTransmission { int DestroyIceTransmission(); int CreateTransmission(const std::string &transmission_id); - int JoinTransmission(const std::string &transmission_id); + int JoinTransmission(const std::string &transmission_id, + const std::string &user_id); + + int SetTransmissionId(const std::string &transmission_id); int SendData(const char *data, size_t size); @@ -55,12 +59,13 @@ class IceTransmission { std::function on_receive_ice_msg_cb_ = nullptr; std::string local_sdp_; std::string remote_sdp_; - std::string remote_ice_username_; std::string local_candidates_; std::string remote_candidates_; unsigned int connection_id_ = 0; std::string transmission_id_ = ""; + std::string user_id_ = ""; bool offer_peer_ = true; + std::string remote_ice_username_ = ""; }; #endif \ No newline at end of file diff --git a/src/interface/x.h b/src/interface/x.h index d46e277..a8f9640 100644 --- a/src/interface/x.h +++ b/src/interface/x.h @@ -1,38 +1,39 @@ -#ifndef _X_H_ -#define _X_H_ - -#include -#include - -enum ws_status { WS_CONNECTING = 0, WS_OPEN, WS_FAILED, WS_CLOSED, WS_UNKNOWN }; - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct Peer PeerPtr; - -typedef void (*OnReceiveBuffer)(unsigned char*, size_t, const char*, - const size_t); - -typedef void (*NetStatusReport)(const unsigned short, const unsigned short); - -typedef struct { - const char* cfg_path; - OnReceiveBuffer on_receive_buffer; - NetStatusReport net_status_report; -} Params; - -PeerPtr* CreatePeer(const Params* params); - -int CreateConnection(PeerPtr* peer_ptr); - -int JoinConnection(PeerPtr* peer_ptr, const char* connection_id); - -int SendData(PeerPtr* peer_ptr, const char* data, size_t size); - -#ifdef __cplusplus -} -#endif - +#ifndef _X_H_ +#define _X_H_ + +#include +#include + +enum ws_status { WS_CONNECTING = 0, WS_OPEN, WS_FAILED, WS_CLOSED, WS_UNKNOWN }; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Peer PeerPtr; + +typedef void (*OnReceiveBuffer)(unsigned char*, size_t, const char*, + const size_t); + +typedef void (*NetStatusReport)(const unsigned short, const unsigned short); + +typedef struct { + const char* cfg_path; + OnReceiveBuffer on_receive_buffer; + NetStatusReport net_status_report; +} Params; + +PeerPtr* CreatePeer(const Params* params); + +int CreateConnection(PeerPtr* peer_ptr); + +int JoinConnection(PeerPtr* peer_ptr, const char* transmission_id, + const char* user_id); + +int SendData(PeerPtr* peer_ptr, const char* data, size_t size); + +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/src/log/log.h b/src/log/log.h index 831b37d..71c690c 100644 --- a/src/log/log.h +++ b/src/log/log.h @@ -1,127 +1,127 @@ -#ifndef _LOG_H_ -#define _LOG_H_ - -#include -#include -#include -#include -#include - -#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 sinks; \ - sinks.push_back(std::make_shared()); \ - sinks.push_back(std::make_shared( \ - path, 1048576 * 5, 3)); \ - auto combined_logger = std::make_shared( \ - 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 sinks; \ - sinks.push_back(std::make_shared()); \ - sinks.push_back(std::make_shared( \ - path, 1048576 * 5, 3)); \ - auto combined_logger = std::make_shared( \ - 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 sinks; \ - sinks.push_back(std::make_shared()); \ - sinks.push_back(std::make_shared( \ - path, 1048576 * 5, 3)); \ - auto combined_logger = std::make_shared( \ - 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 sinks; \ - sinks.push_back(std::make_shared()); \ - sinks.push_back(std::make_shared( \ - path, 1048576 * 5, 3)); \ - auto combined_logger = std::make_shared( \ - 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 +#ifndef _LOG_H_ +#define _LOG_H_ + +#include +#include +#include +#include +#include + +#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 sinks; \ + sinks.push_back(std::make_shared()); \ + sinks.push_back(std::make_shared( \ + path, 1048576 * 5, 3)); \ + auto combined_logger = std::make_shared( \ + 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 sinks; \ + sinks.push_back(std::make_shared()); \ + sinks.push_back(std::make_shared( \ + path, 1048576 * 5, 3)); \ + auto combined_logger = std::make_shared( \ + 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 sinks; \ + sinks.push_back(std::make_shared()); \ + sinks.push_back(std::make_shared( \ + path, 1048576 * 5, 3)); \ + auto combined_logger = std::make_shared( \ + 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 sinks; \ + sinks.push_back(std::make_shared()); \ + sinks.push_back(std::make_shared( \ + path, 1048576 * 5, 3)); \ + auto combined_logger = std::make_shared( \ + 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 diff --git a/src/pc/peer_connection.cpp b/src/pc/peer_connection.cpp index ac17b21..aef5026 100644 --- a/src/pc/peer_connection.cpp +++ b/src/pc/peer_connection.cpp @@ -1,257 +1,320 @@ -#include "peer_connection.h" - -#include - -#include "INIReader.h" -#include "common.h" -#include "log.h" -#include "nlohmann/json.hpp" - -using nlohmann::json; - -static const std::map siganl_types{ - {"ws_connection_id", 1}, - {"offer", 2}, - {"transmission_id", 3}, - {"remote_sdp", 4}, - {"candidate", 5}}; - -PeerConnection::PeerConnection() {} - -PeerConnection::~PeerConnection() {} - -int PeerConnection::Create(PeerConnectionParams params, - const std::string &transmission_id) { - INIReader reader(params.cfg_path); - cfg_signal_server_ip_ = reader.Get("signal server", "ip", "-1"); - cfg_signal_server_port_ = reader.Get("signal server", "port", "-1"); - cfg_stun_server_ip_ = reader.Get("stun server", "ip", "-1"); - cfg_stun_server_port_ = reader.Get("stun server", "port", "-1"); - std::regex regex("\n"); - - LOG_INFO("Read config success"); - - signal_server_port_ = stoi(cfg_signal_server_port_); - stun_server_port_ = stoi(cfg_stun_server_port_); - - on_receive_ws_msg_ = [this](const std::string &msg) { - auto j = json::parse(msg); - std::string type = j["type"]; - LOG_INFO("msg type :{}", type.c_str()); - switch (HASH_STRING_PIECE(type.c_str())) { - case "ws_connection_id"_H: { - ws_connection_id_ = j["ws_connection_id"].get(); - LOG_INFO("Receive local peer websocket connection id [{}]", - ws_connection_id_); - signal_status_ = SignalStatus::Connected; - break; - } - case "transmission_id"_H: { - if (j["status"].get() == "success") { - transmission_id_ = j["transmission_id"].get(); - LOG_INFO("Create transmission success with id [{}]", - transmission_id_); - - } else if (j["status"].get() == "fail") { - LOG_WARN("Create transmission failed with id [{}], due to [{}]", - transmission_id_, j["reason"].get().c_str()); - } - break; - } - case "offer"_H: { - std::string remote_sdp = j["sdp"].get(); - - if (remote_sdp.empty()) { - LOG_INFO("Invalid remote sdp"); - } else { - std::string ice_username = GetIceUsername(remote_sdp); - LOG_INFO("Receive remote sdp from [{}]", ice_username); - - // IceTransmission *ice_transmission = - // new IceTransmission(false, ws_transport_, on_receive_ice_msg_); - - ice_transmission_list_[ice_username] = - new IceTransmission(false, ws_transport_, on_receive_ice_msg_); - ice_transmission_list_[ice_username]->InitIceTransmission( - cfg_stun_server_ip_, stun_server_port_); - - ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); - - ice_transmission_list_[ice_username]->GatherCandidates(); - } - break; - } - default: { - // ice_transmission_->OnReceiveMessage(msg); - break; - } - } - }; - - on_receive_ice_msg_ = [this](const char *data, size_t size) { - std::string msg(data, size); - LOG_INFO("Receive data: [{}]", msg.c_str()); - }; - - ws_transport_ = new WsTransmission(on_receive_ws_msg_); - uri_ = "ws://" + cfg_signal_server_ip_ + ":" + cfg_signal_server_port_; - if (ws_transport_) { - ws_transport_->Connect(uri_); - } - - do { - LOG_INFO("GetSignalStatus = {}", GetSignalStatus()); - } while (SignalStatus::Connected != GetSignalStatus()); - - // ice_transmission_->CreateTransmission(transmission_id); - - json message = {{"type", "create_transmission"}, - {"transmission_id", transmission_id}}; - if (ws_transport_) { - ws_transport_->Send(message.dump()); - LOG_INFO("Send create transmission request: {}", message.dump().c_str()); - } - return 0; -} - -int PeerConnection::Join(PeerConnectionParams params, - const std::string &transmission_id) { - INIReader reader(params.cfg_path); - cfg_signal_server_ip_ = reader.Get("signal server", "ip", "-1"); - cfg_signal_server_port_ = reader.Get("signal server", "port", "-1"); - cfg_stun_server_ip_ = reader.Get("stun server", "ip", "-1"); - cfg_stun_server_port_ = reader.Get("stun server", "port", "-1"); - std::regex regex("\n"); - - LOG_INFO("Read config success"); - - signal_server_port_ = stoi(cfg_signal_server_port_); - stun_server_port_ = stoi(cfg_stun_server_port_); - - on_receive_ws_msg_ = [this](const std::string &msg) { - do { - } while (ice_transmission_list_.empty()); - auto j = json::parse(msg); - std::string type = j["type"]; - LOG_INFO("msg type :{}", type.c_str()); - switch (HASH_STRING_PIECE(type.c_str())) { - case "ws_connection_id"_H: { - ws_connection_id_ = j["ws_connection_id"].get(); - LOG_INFO("Receive local peer websocket connection id [{}]", - ws_connection_id_); - signal_status_ = SignalStatus::Connected; - break; - } - case "offer"_H: { - std::string remote_sdp = j["sdp"].get(); - - if (remote_sdp.empty()) { - LOG_INFO("Invalid remote sdp"); - } else { - std::string ice_username = GetIceUsername(remote_sdp); - LOG_INFO("Receive remote sdp from [{}]", ice_username); - - // IceTransmission *ice_transmission = - // new IceTransmission(false, ws_transport_, on_receive_ice_msg_); - - ice_transmission_list_[ice_username] = - new IceTransmission(false, ws_transport_, on_receive_ice_msg_); - ice_transmission_list_[ice_username]->InitIceTransmission( - cfg_stun_server_ip_, stun_server_port_); - - ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); - - ice_transmission_list_[ice_username]->GatherCandidates(); - } - break; - } - case "remote_sdp"_H: { - std::string remote_sdp = j["sdp"].get(); - if (remote_sdp.empty()) { - LOG_INFO("remote_sdp is empty"); - } else { - std::string ice_username = GetIceUsername(remote_sdp); - LOG_INFO("Receive remote sdp from [{}]", ice_username); - // LOG_INFO("Receive remote sdp [{}]", remote_sdp); - - if (ice_transmission_list_.size() == 1 && - ice_transmission_list_.begin()->first == "self") { - ice_transmission_list_["self"]->SetRemoteSdp(remote_sdp); - } else if (ice_transmission_list_.find(ice_username) == - ice_transmission_list_.end()) { - ice_transmission_list_[ice_username] = - new IceTransmission(false, ws_transport_, on_receive_ice_msg_); - ice_transmission_list_[ice_username]->InitIceTransmission( - cfg_stun_server_ip_, stun_server_port_); - ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); - } - - // if (!offer_peer_) { - // GatherCandidates(); - // } - } - break; - } - case "candidate"_H: { - std::string remote_sdp_with_candidates = j["sdp"].get(); - std::string ice_username = GetIceUsername(remote_sdp_with_candidates); - LOG_INFO("Receive remote candidates from [{}]", ice_username); - // LOG_INFO("Receive candidate [{}]", candidate); - - ice_transmission_list_[ice_username]->AddRemoteCandidate( - remote_sdp_with_candidates); - break; - } - default: { - ice_transmission_->OnReceiveMessage(msg); - break; - } - } - }; - - on_receive_ice_msg_ = [this](const char *data, size_t size) { - std::string msg(data, size); - LOG_INFO("Receive data: [{}]", msg.c_str()); - }; - - transmission_id_ = transmission_id; - - ws_transport_ = new WsTransmission(on_receive_ws_msg_); - uri_ = "ws://" + cfg_signal_server_ip_ + ":" + cfg_signal_server_port_; - if (ws_transport_) { - ws_transport_->Connect(uri_); - } - - ice_transmission_list_["self"] = - new IceTransmission(true, ws_transport_, on_receive_ice_msg_); - ice_transmission_list_["self"]->InitIceTransmission(cfg_stun_server_ip_, - stun_server_port_); - // ice_transmission_ = - // new IceTransmission(true, ws_transport_, on_receive_ice_msg_); - // ice_transmission_->InitIceTransmission(cfg_stun_server_ip, - // stun_server_port); - - do { - // LOG_INFO("GetSignalStatus = {}", GetSignalStatus()); - } while (SignalStatus::Connected != GetSignalStatus()); - - // ice_transmission_->JoinTransmission(transmission_id_); - ice_transmission_list_["self"]->JoinTransmission(transmission_id_); - return 0; -} - -int PeerConnection::Destroy() { - if (ws_transport_) { - delete ws_transport_; - } - return 0; -} - -SignalStatus PeerConnection::GetSignalStatus() { return signal_status_; } - -int PeerConnection::SendData(const char *data, size_t size) { - for (auto ice_trans : ice_transmission_list_) { - ice_trans.second->SendData(data, size); - } - return 0; +#include "peer_connection.h" + +#include + +#include "INIReader.h" +#include "common.h" +#include "log.h" +#include "nlohmann/json.hpp" + +using nlohmann::json; + +static const std::map siganl_types{ + {"ws_connection_id", 1}, + {"offer", 2}, + {"transmission_id", 3}, + {"remote_sdp", 4}, + {"candidate", 5}}; + +PeerConnection::PeerConnection() {} + +PeerConnection::~PeerConnection() {} + +int PeerConnection::Create(PeerConnectionParams params, + const std::string &transmission_id, + const std::string &user_id) { + user_id_ = user_id; + + INIReader reader(params.cfg_path); + cfg_signal_server_ip_ = reader.Get("signal server", "ip", "-1"); + cfg_signal_server_port_ = reader.Get("signal server", "port", "-1"); + cfg_stun_server_ip_ = reader.Get("stun server", "ip", "-1"); + cfg_stun_server_port_ = reader.Get("stun server", "port", "-1"); + std::regex regex("\n"); + + LOG_INFO("Read config success"); + + signal_server_port_ = stoi(cfg_signal_server_port_); + stun_server_port_ = stoi(cfg_stun_server_port_); + + on_receive_ws_msg_ = [this](const std::string &msg) { + auto j = json::parse(msg); + std::string type = j["type"]; + LOG_INFO("msg type :{}", type.c_str()); + switch (HASH_STRING_PIECE(type.c_str())) { + case "ws_connection_id"_H: { + ws_connection_id_ = j["ws_connection_id"].get(); + LOG_INFO("Receive local peer websocket connection id [{}]", + ws_connection_id_); + signal_status_ = SignalStatus::Connected; + break; + } + case "transmission_id"_H: { + if (j["status"].get() == "success") { + transmission_id_ = j["transmission_id"].get(); + LOG_INFO("Create transmission success with id [{}]", + transmission_id_); + + } else if (j["status"].get() == "fail") { + LOG_WARN("Create transmission failed with id [{}], due to [{}]", + transmission_id_, j["reason"].get().c_str()); + } + break; + } + case "offer"_H: { + std::string remote_sdp = j["sdp"].get(); + + if (remote_sdp.empty()) { + LOG_INFO("Invalid remote sdp"); + } else { + std::string ice_username = GetIceUsername(remote_sdp); + LOG_INFO("Receive remote sdp from [{}]", ice_username); + + // IceTransmission *ice_transmission = + // new IceTransmission(false, ws_transport_, on_receive_ice_msg_); + + ice_transmission_list_[ice_username] = new IceTransmission( + false, ice_username, ws_transport_, on_receive_ice_msg_); + + ice_transmission_list_[ice_username]->InitIceTransmission( + cfg_stun_server_ip_, stun_server_port_); + + ice_transmission_list_[ice_username]->SetTransmissionId( + transmission_id_); + + ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); + + ice_transmission_list_[ice_username]->GatherCandidates(); + } + break; + } + default: { + // ice_transmission_->OnReceiveMessage(msg); + break; + } + } + }; + + on_receive_ice_msg_ = [this](const char *data, size_t size) { + std::string msg(data, size); + LOG_INFO("Receive data: [{}]", msg.c_str()); + }; + + ws_transport_ = new WsTransmission(on_receive_ws_msg_); + uri_ = "ws://" + cfg_signal_server_ip_ + ":" + cfg_signal_server_port_; + if (ws_transport_) { + ws_transport_->Connect(uri_); + } + + do { + LOG_INFO("GetSignalStatus = {}", GetSignalStatus()); + } while (SignalStatus::Connected != GetSignalStatus()); + + json message = {{"type", "create_transmission"}, + {"user_id", user_id}, + {"transmission_id", transmission_id}}; + if (ws_transport_) { + ws_transport_->Send(message.dump()); + LOG_INFO("Send create transmission request: {}", message.dump().c_str()); + } + return 0; +} + +int PeerConnection::Join(PeerConnectionParams params, + const std::string &transmission_id, + const std::string &user_id) { + // Todo: checkout user_id unique or not + user_id_ = user_id; + + INIReader reader(params.cfg_path); + cfg_signal_server_ip_ = reader.Get("signal server", "ip", "-1"); + cfg_signal_server_port_ = reader.Get("signal server", "port", "-1"); + cfg_stun_server_ip_ = reader.Get("stun server", "ip", "-1"); + cfg_stun_server_port_ = reader.Get("stun server", "port", "-1"); + std::regex regex("\n"); + + LOG_INFO("Read config success"); + + signal_server_port_ = stoi(cfg_signal_server_port_); + stun_server_port_ = stoi(cfg_stun_server_port_); + + on_receive_ws_msg_ = [this](const std::string &msg) { + // do { + // } while (ice_transmission_list_.empty()); + auto j = json::parse(msg); + std::string type = j["type"]; + LOG_INFO("msg type :{}", type); + switch (HASH_STRING_PIECE(type.c_str())) { + case "transmission_members"_H: { + transmission_member_list_ = j["transmission_members"]; + std::string transmission_id = j["transmission_id"]; + + LOG_INFO("Transmission [{}] members: [", transmission_id); + for (auto member : transmission_member_list_) { + LOG_INFO("{}", member); + } + LOG_INFO("]"); + + if (transmission_member_list_.size() == 1 && + transmission_member_list_[0] == "host") { + ice_transmission_list_["host"] = new IceTransmission( + true, "host", ws_transport_, on_receive_ice_msg_); + ice_transmission_list_["host"]->InitIceTransmission( + cfg_stun_server_ip_, stun_server_port_); + ice_transmission_list_["host"]->JoinTransmission(transmission_id, + user_id_); + } else { + for (auto &member : transmission_member_list_) { + ice_transmission_list_[member] = new IceTransmission( + true, member, ws_transport_, on_receive_ice_msg_); + ice_transmission_list_[member]->InitIceTransmission( + cfg_stun_server_ip_, stun_server_port_); + ice_transmission_list_[member]->JoinTransmission(transmission_id, + user_id_); + } + } + + break; + } + case "ws_connection_id"_H: { + ws_connection_id_ = j["ws_connection_id"].get(); + LOG_INFO("Receive local peer websocket connection id [{}]", + ws_connection_id_); + signal_status_ = SignalStatus::Connected; + break; + } + case "offer"_H: { + std::string remote_sdp = j["sdp"].get(); + + if (remote_sdp.empty()) { + LOG_INFO("Invalid remote sdp"); + } else { + std::string ice_username = GetIceUsername(remote_sdp); + LOG_INFO("Receive remote sdp from [{}]", ice_username); + + // IceTransmission *ice_transmission = + // new IceTransmission(false, ws_transport_, on_receive_ice_msg_); + + ice_transmission_list_[ice_username] = new IceTransmission( + false, ice_username, ws_transport_, on_receive_ice_msg_); + ice_transmission_list_[ice_username]->InitIceTransmission( + cfg_stun_server_ip_, stun_server_port_); + + ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); + + ice_transmission_list_[ice_username]->GatherCandidates(); + } + break; + } + case "remote_sdp"_H: { + std::string remote_sdp = j["sdp"].get(); + if (remote_sdp.empty()) { + LOG_INFO("remote_sdp is empty"); + } else { + std::string ice_username = GetIceUsername(remote_sdp); + LOG_INFO("Receive remote sdp from [{}]", ice_username); + // LOG_INFO("Receive remote sdp [{}]", remote_sdp); + + // if (ice_transmission_list_.size() == 1 && + // ice_transmission_list_.begin()->first == "host") { + // ice_transmission_list_["host"]->SetRemoteSdp(remote_sdp); + // } else if (ice_transmission_list_.find(ice_username) == + // ice_transmission_list_.end()) { + // ice_transmission_list_[ice_username] = new IceTransmission( + // false, ice_username, ws_transport_, on_receive_ice_msg_); + // ice_transmission_list_[ice_username]->InitIceTransmission( + // cfg_stun_server_ip_, stun_server_port_); + // ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); + // } + + if (ice_transmission_list_.size() == 1 && + ice_transmission_list_.begin()->first == "host") { + ice_transmission_list_["host"]->SetRemoteSdp(remote_sdp); + } else if (ice_transmission_list_.find(ice_username) != + ice_transmission_list_.end()) { + ice_transmission_list_[ice_username]->SetRemoteSdp(remote_sdp); + } + + // if (!offer_peer_) { + // GatherCandidates(); + // } + } + break; + } + case "candidate"_H: { + std::string remote_sdp_with_candidates = j["sdp"].get(); + std::string ice_username = GetIceUsername(remote_sdp_with_candidates); + LOG_INFO("Receive remote candidates from [{}]", ice_username); + // LOG_INFO("Receive candidate [{}]", candidate); + + ice_transmission_list_[ice_username]->AddRemoteCandidate( + remote_sdp_with_candidates); + break; + } + default: { + ice_transmission_->OnReceiveMessage(msg); + break; + } + } + }; + + on_receive_ice_msg_ = [this](const char *data, size_t size) { + std::string msg(data, size); + LOG_INFO("Receive data: [{}]", msg.c_str()); + }; + + transmission_id_ = transmission_id; + + ws_transport_ = new WsTransmission(on_receive_ws_msg_); + uri_ = "ws://" + cfg_signal_server_ip_ + ":" + cfg_signal_server_port_; + if (ws_transport_) { + ws_transport_->Connect(uri_); + } + + // ice_transmission_list_["self"] = + // new IceTransmission(true, ws_transport_, on_receive_ice_msg_); + // ice_transmission_list_["self"]->InitIceTransmission(cfg_stun_server_ip_, + // stun_server_port_); + // ice_transmission_ = + // new IceTransmission(true, ws_transport_, on_receive_ice_msg_); + // ice_transmission_->InitIceTransmission(cfg_stun_server_ip, + // stun_server_port); + + do { + // LOG_INFO("GetSignalStatus = {}", GetSignalStatus()); + } while (SignalStatus::Connected != GetSignalStatus()); + + RequestTransmissionMemberList(transmission_id_); + // ice_transmission_->JoinTransmission(transmission_id_); + // ice_transmission_list_["self"]->JoinTransmission(transmission_id_); + return 0; +} + +int PeerConnection::RequestTransmissionMemberList( + const std::string &transmission_id) { + LOG_INFO("Request member list"); + + json message = {{"type", "query_members"}, + {"transmission_id", transmission_id_}}; + + if (ws_transport_) { + ws_transport_->Send(message.dump()); + } + return 0; +} + +int PeerConnection::Destroy() { + if (ws_transport_) { + delete ws_transport_; + } + return 0; +} + +SignalStatus PeerConnection::GetSignalStatus() { return signal_status_; } + +int PeerConnection::SendData(const char *data, size_t size) { + for (auto ice_trans : ice_transmission_list_) { + ice_trans.second->SendData(data, size); + } + return 0; } \ No newline at end of file diff --git a/src/pc/peer_connection.h b/src/pc/peer_connection.h index a585773..271e314 100644 --- a/src/pc/peer_connection.h +++ b/src/pc/peer_connection.h @@ -1,55 +1,62 @@ -#ifndef _PEER_CONNECTION_H_ -#define _PEER_CONNECTION_H_ - -#include -#include - -#include "ice_transmission.h" -#include "ws_transmission.h" - -enum SignalStatus { Connecting = 0, Connected, Closed }; - -typedef void (*OnReceiveBuffer)(unsigned char *, size_t, const char *, - const size_t); - -typedef void (*NetStatusReport)(const unsigned short, const unsigned short); - -typedef struct { - const char *cfg_path; - OnReceiveBuffer on_receive_buffer; - NetStatusReport net_status_report; -} PeerConnectionParams; - -class PeerConnection { - public: - PeerConnection(); - ~PeerConnection(); - - public: - int Create(PeerConnectionParams params, const std::string &id = ""); - int Join(PeerConnectionParams params, const std::string &id); - int Destroy(); - - SignalStatus GetSignalStatus(); - - int SendData(const char *data, size_t size); - - private: - std::string uri_ = ""; - std::string cfg_signal_server_ip_; - std::string cfg_signal_server_port_; - std::string cfg_stun_server_ip_; - std::string cfg_stun_server_port_; - int signal_server_port_ = 0; - int stun_server_port_ = 0; - WsTransmission *ws_transport_ = nullptr; - IceTransmission *ice_transmission_ = nullptr; - std::map ice_transmission_list_; - std::function on_receive_ws_msg_ = nullptr; - std::function on_receive_ice_msg_ = nullptr; - unsigned int ws_connection_id_ = 0; - std::string transmission_id_ = ""; - SignalStatus signal_status_ = SignalStatus::Closed; -}; - +#ifndef _PEER_CONNECTION_H_ +#define _PEER_CONNECTION_H_ + +#include +#include + +#include "ice_transmission.h" +#include "ws_transmission.h" + +enum SignalStatus { Connecting = 0, Connected, Closed }; + +typedef void (*OnReceiveBuffer)(unsigned char *, size_t, const char *, + const size_t); + +typedef void (*NetStatusReport)(const unsigned short, const unsigned short); + +typedef struct { + const char *cfg_path; + OnReceiveBuffer on_receive_buffer; + NetStatusReport net_status_report; +} PeerConnectionParams; + +class PeerConnection { + public: + PeerConnection(); + ~PeerConnection(); + + public: + int Create(PeerConnectionParams params, + const std::string &transmission_id = "", + const std::string &user_id = ""); + int Join(PeerConnectionParams params, const std::string &transmission_id, + const std::string &user_id = ""); + int Destroy(); + + int RequestTransmissionMemberList(const std::string &transmission_id); + + SignalStatus GetSignalStatus(); + + int SendData(const char *data, size_t size); + + private: + std::string uri_ = ""; + std::string cfg_signal_server_ip_; + std::string cfg_signal_server_port_; + std::string cfg_stun_server_ip_; + std::string cfg_stun_server_port_; + int signal_server_port_ = 0; + int stun_server_port_ = 0; + WsTransmission *ws_transport_ = nullptr; + IceTransmission *ice_transmission_ = nullptr; + std::vector transmission_member_list_; + std::map ice_transmission_list_; + std::function on_receive_ws_msg_ = nullptr; + std::function on_receive_ice_msg_ = nullptr; + unsigned int ws_connection_id_ = 0; + std::string user_id_ = ""; + std::string transmission_id_ = ""; + SignalStatus signal_status_ = SignalStatus::Closed; +}; + #endif \ No newline at end of file diff --git a/src/rtc/x_inner.cpp b/src/rtc/x_inner.cpp index c6b71db..df93927 100644 --- a/src/rtc/x_inner.cpp +++ b/src/rtc/x_inner.cpp @@ -1,45 +1,49 @@ -#include "x_inner.h" - -#include -#include - -#include "ice_agent.h" -#include "log.h" -#include "ws_transmission.h" -#include "x.h" - -using nlohmann::json; - -static PeerConnection *peer_connection; - -PeerPtr *CreatePeer(const Params *params) { - PeerPtr *peer_ptr = new PeerPtr; - peer_ptr->peer_connection = new PeerConnection(); - peer_ptr->pc_params.cfg_path = params->cfg_path; - peer_ptr->pc_params.on_receive_buffer = params->on_receive_buffer; - peer_ptr->pc_params.net_status_report = params->net_status_report; - - return peer_ptr; -} - -int CreateConnection(PeerPtr *peer_ptr) { - peer_ptr->peer_connection->Create(peer_ptr->pc_params); - return 0; -} - -int CreateConnection(PeerPtr *peer_ptr, const char *connection_id) { - peer_ptr->peer_connection->Create(peer_ptr->pc_params, connection_id); - return 0; -} - -int JoinConnection(PeerPtr *peer_ptr, const char *connection_id) { - peer_ptr->peer_connection->Join(peer_ptr->pc_params, connection_id); - return 0; -} - -int SendData(PeerPtr *peer_ptr, const char *data, size_t size) { - peer_ptr->peer_connection->SendData(data, size); - return 0; -} - +#include "x_inner.h" + +#include +#include + +#include "ice_agent.h" +#include "log.h" +#include "ws_transmission.h" +#include "x.h" + +using nlohmann::json; + +static PeerConnection *peer_connection; + +PeerPtr *CreatePeer(const Params *params) { + PeerPtr *peer_ptr = new PeerPtr; + peer_ptr->peer_connection = new PeerConnection(); + peer_ptr->pc_params.cfg_path = params->cfg_path; + peer_ptr->pc_params.on_receive_buffer = params->on_receive_buffer; + peer_ptr->pc_params.net_status_report = params->net_status_report; + + return peer_ptr; +} + +int CreateConnection(PeerPtr *peer_ptr) { + peer_ptr->peer_connection->Create(peer_ptr->pc_params); + return 0; +} + +int CreateConnection(PeerPtr *peer_ptr, const char *transmission_id, + const char *user_id) { + peer_ptr->peer_connection->Create(peer_ptr->pc_params, transmission_id, + user_id); + return 0; +} + +int JoinConnection(PeerPtr *peer_ptr, const char *transmission_id, + const char *user_id) { + peer_ptr->peer_connection->Join(peer_ptr->pc_params, transmission_id, + user_id); + return 0; +} + +int SendData(PeerPtr *peer_ptr, const char *data, size_t size) { + peer_ptr->peer_connection->SendData(data, size); + return 0; +} + int rtc() { return 0; } \ No newline at end of file diff --git a/src/rtc/x_inner.h b/src/rtc/x_inner.h index bf65c53..9906afd 100644 --- a/src/rtc/x_inner.h +++ b/src/rtc/x_inner.h @@ -1,11 +1,11 @@ -#ifndef _X_INNER_H_ -#define _X_INNER_H_ - -#include "peer_connection.h" - -struct Peer { - PeerConnection *peer_connection; - PeerConnectionParams pc_params; -}; - +#ifndef _X_INNER_H_ +#define _X_INNER_H_ + +#include "peer_connection.h" + +struct Peer { + PeerConnection *peer_connection; + PeerConnectionParams pc_params; +}; + #endif \ No newline at end of file diff --git a/src/ws/ws_core.cpp b/src/ws/ws_core.cpp index a14326b..793acf6 100644 --- a/src/ws/ws_core.cpp +++ b/src/ws/ws_core.cpp @@ -1,136 +1,136 @@ -#include "ws_core.h" - -#include -#include -#include - -#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( - &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()); +#include "ws_core.h" + +#include +#include +#include + +#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( + &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()); } \ No newline at end of file diff --git a/src/ws/ws_core.h b/src/ws/ws_core.h index dfb2e9d..01c8fa3 100644 --- a/src/ws/ws_core.h +++ b/src/ws/ws_core.h @@ -1,54 +1,54 @@ -#ifndef _WS_CORE_H_ -#define _WS_CORE_H_ - -#include -#include -#include - -#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 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 m_thread_; - - std::string connection_status_ = "Connecting"; -}; - +#ifndef _WS_CORE_H_ +#define _WS_CORE_H_ + +#include +#include +#include + +#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 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 m_thread_; + + std::string connection_status_ = "Connecting"; +}; + #endif \ No newline at end of file diff --git a/src/ws/ws_transmission.cpp b/src/ws/ws_transmission.cpp index ad59c3f..c582794 100644 --- a/src/ws/ws_transmission.cpp +++ b/src/ws/ws_transmission.cpp @@ -1,16 +1,16 @@ -#include "ws_transmission.h" - -#include "log.h" - -WsTransmission::WsTransmission( - std::function on_receive_msg_cb) - : on_receive_msg_(on_receive_msg_cb) {} - -WsTransmission::~WsTransmission() {} - -void WsTransmission::OnReceiveMessage(const std::string &msg) { - // LOG_INFO("Receive msg: {}", msg); - if (on_receive_msg_) { - on_receive_msg_(msg); - } +#include "ws_transmission.h" + +#include "log.h" + +WsTransmission::WsTransmission( + std::function on_receive_msg_cb) + : on_receive_msg_(on_receive_msg_cb) {} + +WsTransmission::~WsTransmission() {} + +void WsTransmission::OnReceiveMessage(const std::string &msg) { + // LOG_INFO("Receive msg: {}", msg); + if (on_receive_msg_) { + on_receive_msg_(msg); + } } \ No newline at end of file diff --git a/src/ws/ws_transmission.h b/src/ws/ws_transmission.h index d2f8be7..a527087 100644 --- a/src/ws/ws_transmission.h +++ b/src/ws/ws_transmission.h @@ -1,18 +1,18 @@ -#ifndef _WS_TRANSMISSION_H_ -#define _WS_TRANSMISSION_H_ - -#include "ws_core.h" - -class WsTransmission : public WsCore { - public: - WsTransmission(std::function on_receive_msg_cb); - ~WsTransmission(); - - public: - void OnReceiveMessage(const std::string &msg); - - private: - std::function on_receive_msg_ = nullptr; -}; - +#ifndef _WS_TRANSMISSION_H_ +#define _WS_TRANSMISSION_H_ + +#include "ws_core.h" + +class WsTransmission : public WsCore { + public: + WsTransmission(std::function on_receive_msg_cb); + ~WsTransmission(); + + public: + void OnReceiveMessage(const std::string &msg); + + private: + std::function on_receive_msg_ = nullptr; +}; + #endif \ No newline at end of file diff --git a/tests/peerconnection/guest.cpp b/tests/peerconnection/guest.cpp index a816a99..43166c8 100644 --- a/tests/peerconnection/guest.cpp +++ b/tests/peerconnection/guest.cpp @@ -1,27 +1,28 @@ -#include - -#include "x.h" - -int main(int argc, char** argv) { - Params params; - params.cfg_path = "../../../../config/config.ini"; - - std::string transmission_id = "000000"; - // std::cout << "Please input which transmisson want to join: "; - // std::cin >> transmission_id; - - PeerPtr* peer = CreatePeer(¶ms); - JoinConnection(peer, transmission_id.c_str()); - - std::string msg = "Offer peer"; - - int i = 100; - while (i--) { - getchar(); - std::cout << "Send data: [" << msg << "]" << std::endl; - SendData(peer, msg.data(), msg.size()); - } - - getchar(); - return 0; -} +#include + +#include "x.h" + +int main(int argc, char** argv) { + Params params; + params.cfg_path = "../../../../config/config.ini"; + + std::string transmission_id = "000000"; + std::string user_id = argv[1]; + // std::cout << "Please input which transmisson want to join: "; + // std::cin >> transmission_id; + + PeerPtr* peer = CreatePeer(¶ms); + JoinConnection(peer, transmission_id.c_str(), user_id.c_str()); + + std::string msg = "Offer peer"; + + int i = 100; + while (i--) { + getchar(); + std::cout << "Send data: [" << msg << "]" << std::endl; + SendData(peer, msg.data(), msg.size()); + } + + getchar(); + return 0; +} diff --git a/tests/peerconnection/host.cpp b/tests/peerconnection/host.cpp index b75a621..a0aa789 100644 --- a/tests/peerconnection/host.cpp +++ b/tests/peerconnection/host.cpp @@ -1,23 +1,23 @@ -#include - -#include "x.h" - -int main(int argc, char** argv) { - Params params; - params.cfg_path = "../../../../config/config.ini"; - - PeerPtr* peer = CreatePeer(¶ms); - CreateConnection(peer); - - std::string msg = "Answer peer"; - - int i = 100; - while (i--) { - getchar(); - std::cout << "Send data: [" << msg << "]" << std::endl; - SendData(peer, msg.data(), msg.size()); - } - - getchar(); - return 0; -} +#include + +#include "x.h" + +int main(int argc, char** argv) { + Params params; + params.cfg_path = "../../../../config/config.ini"; + + PeerPtr* peer = CreatePeer(¶ms); + CreateConnection(peer); + + std::string msg = "Answer peer"; + + int i = 100; + while (i--) { + getchar(); + std::cout << "Send data: [" << msg << "]" << std::endl; + SendData(peer, msg.data(), msg.size()); + } + + getchar(); + return 0; +} diff --git a/tests/signal_server/main.cpp b/tests/signal_server/main.cpp index eb8927e..7892f22 100644 --- a/tests/signal_server/main.cpp +++ b/tests/signal_server/main.cpp @@ -1,17 +1,17 @@ - -#include - -#include "signal_server.h" - -int main(int argc, char* argv[]) { - SignalServer s; - std::string port = ""; - if (argc > 1) { - port = argv[1]; - } else { - port = "9090"; - } - std::cout << "Port: " << port << std::endl; - s.run(std::stoi(port)); - return 0; + +#include + +#include "signal_server.h" + +int main(int argc, char* argv[]) { + SignalServer s; + std::string port = ""; + if (argc > 1) { + port = argv[1]; + } else { + port = "9090"; + } + std::cout << "Port: " << port << std::endl; + s.run(std::stoi(port)); + return 0; } \ No newline at end of file diff --git a/tests/signal_server/signal_server.cpp b/tests/signal_server/signal_server.cpp index 7d3c657..a753e9a 100644 --- a/tests/signal_server/signal_server.cpp +++ b/tests/signal_server/signal_server.cpp @@ -72,6 +72,7 @@ bool SignalServer::on_pong(websocketpp::connection_hdl hdl, std::string s) { } void SignalServer::run(uint16_t port) { + server_.set_reuse_addr(true); server_.listen(port); // Queues a connection accept operation @@ -95,6 +96,7 @@ void SignalServer::on_message(websocketpp::connection_hdl hdl, switch (HASH_STRING_PIECE(type.c_str())) { case "create_transmission"_H: { std::string transmission_id = j["transmission_id"].get(); + std::string user_id = j["user_id"].get(); LOG_INFO("Receive create transmission request with id [{}]", transmission_id); if (transmission_list_.find(transmission_id) == @@ -111,7 +113,16 @@ void SignalServer::on_message(websocketpp::connection_hdl hdl, transmission_id); } transmission_list_.insert(transmission_id); - transmission_manager_.BindHostToTransmission(hdl, transmission_id); + + transmission_manager_.BindWsHandleToTransmission(hdl, transmission_id); + transmission_manager_.BindUserIdToTransmission(user_id, + transmission_id); + transmission_manager_.BindUserIdToWsHandle(user_id, hdl); + transmission_manager_.BindUserNameToUserId("host", user_id); + + // if (transmission_manager_.GetUsername(hdl).empty()) { + // transmission_manager_.BindUsernameToWsHandle("host", hdl); + // } LOG_INFO("Create transmission id [{}]", transmission_id); json message = {{"type", "transmission_id"}, @@ -129,37 +140,6 @@ void SignalServer::on_message(websocketpp::connection_hdl hdl, break; } - case "offer"_H: { - std::string transmission_id = j["transmission_id"].get(); - std::string sdp = j["sdp"].get(); - // LOG_INFO("Receive transmission id [{}] with offer sdp [{}]", - // transmission_id, sdp); - transmission_manager_.BindGuestToTransmission(hdl, transmission_id); - std::string guest_username = GetIceUsername(sdp); - transmission_manager_.BindGuestUsernameToWsHandle(guest_username, hdl); - - websocketpp::connection_hdl host_hdl = - transmission_manager_.GetHostOfTransmission(transmission_id); - std::vector guest_hdl_list = - transmission_manager_.GetAllGuestsOfTransmission(transmission_id); - - // LOG_INFO("send offer sdp [{}]", sdp); - json message = { - {"type", "offer"}, {"sdp", sdp}, {"guest", guest_username}}; - - LOG_INFO("[{}] send offer sdp to host", guest_username); - send_msg(host_hdl, message); - - LOG_INFO("Size of guest_hdl_list: {}", guest_hdl_list.size()); - for (auto guest_hdl : guest_hdl_list) { - if (guest_hdl.lock().get() != hdl.lock().get()) { - LOG_INFO("[{}] send offer sdp to [{}]", guest_username, - transmission_manager_.GetGuestUsername(guest_hdl)); - send_msg(guest_hdl, message); - } - } - break; - } case "query_members"_H: { std::string transmission_id = j["transmission_id"].get(); std::vector member_list = @@ -169,23 +149,44 @@ void SignalServer::on_message(websocketpp::connection_hdl hdl, {"transmission_id", transmission_id}, {"transmission_members", member_list}, {"status", "success"}}; + + LOG_INFO("Send member_list: [{}]", message.dump()); send_msg(hdl, message); break; } + case "offer"_H: { + std::string transmission_id = j["transmission_id"].get(); + std::string sdp = j["sdp"].get(); + std::string remote_peer = j["remote_peer"].get(); + // LOG_INFO("Receive transmission id [{}] with offer sdp [{}]", + // transmission_id, sdp); + transmission_manager_.BindWsHandleToTransmission(hdl, transmission_id); + std::string offer_peer = GetIceUsername(sdp); + transmission_manager_.BindUsernameToWsHandle(offer_peer, hdl); + + websocketpp::connection_hdl destination_hdl = + transmission_manager_.GetWsHandle(remote_peer); + + json message = {{"type", "offer"}, {"sdp", sdp}}; + + LOG_INFO("[{}] send offer sdp to [{}]", offer_peer, remote_peer); + send_msg(destination_hdl, message); + + break; + } case "answer"_H: { std::string transmission_id = j["transmission_id"].get(); std::string sdp = j["sdp"].get(); std::string guest_ice_username = j["guest"].get(); std::string host_ice_username = GetIceUsername(sdp); - if (transmission_manager_.GetHostUsername(hdl).empty()) { - transmission_manager_.BindHostUsernameToWsHandle(host_ice_username, - hdl); + if (transmission_manager_.GetUsername(hdl) == "host") { + LOG_INFO("Update transmission [{}] [host] to [{}]", transmission_id, + host_ice_username); + transmission_manager_.UpdateUsernameToWsHandle(host_ice_username, hdl); } - // LOG_INFO("Receive transmission id [{}] with answer sdp [{}]", - // transmission_id, sdp); websocketpp::connection_hdl guest_hdl = - transmission_manager_.GetGuestWsHandle(guest_ice_username); + transmission_manager_.GetWsHandle(guest_ice_username); // LOG_INFO("send answer sdp [{}]", sdp); LOG_INFO("[{}] send answer sdp to [{}]", host_ice_username, diff --git a/tests/signal_server/signal_server.h b/tests/signal_server/signal_server.h index 6370295..b11f25c 100644 --- a/tests/signal_server/signal_server.h +++ b/tests/signal_server/signal_server.h @@ -1,51 +1,51 @@ -#ifndef _SIGNAL_SERVER_H_ -#define _SIGNAL_SERVER_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include "transmission_manager.h" - -using nlohmann::json; - -typedef websocketpp::server 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(uint16_t port); - - 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> - ws_connections_; - std::map rooms_; - unsigned int ws_connection_id_ = 0; - - std::set transmission_list_; - TransmissionManager transmission_manager_; -}; - +#ifndef _SIGNAL_SERVER_H_ +#define _SIGNAL_SERVER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "transmission_manager.h" + +using nlohmann::json; + +typedef websocketpp::server 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(uint16_t port); + + 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> + ws_connections_; + std::map rooms_; + unsigned int ws_connection_id_ = 0; + + std::set transmission_list_; + TransmissionManager transmission_manager_; +}; + #endif \ No newline at end of file diff --git a/tests/signal_server/transmission_manager.cpp b/tests/signal_server/transmission_manager.cpp index a992d40..9ca0452 100644 --- a/tests/signal_server/transmission_manager.cpp +++ b/tests/signal_server/transmission_manager.cpp @@ -6,101 +6,114 @@ TransmissionManager::TransmissionManager() {} TransmissionManager::~TransmissionManager() {} -bool TransmissionManager::BindHostToTransmission( - websocketpp::connection_hdl hdl, const std::string& transmission_id) { - if (transmission_host_list_.find(transmission_id) != - transmission_host_list_.end()) { - LOG_WARN("Transmission already has a host [{}]", - transmission_host_list_[transmission_id].lock().get()); - return false; - } else { - transmission_host_list_[transmission_id] = hdl; - } - return true; -} +// bool TransmissionManager::BindHostToTransmission( +// websocketpp::connection_hdl hdl, const std::string& transmission_id) { +// if (transmission_host_list_.find(transmission_id) != +// transmission_host_list_.end()) { +// LOG_WARN("Transmission already has a host [{}]", +// transmission_host_list_[transmission_id].lock().get()); +// return false; +// } else { +// transmission_host_list_[transmission_id] = hdl; +// } +// return true; +// } -bool TransmissionManager::BindGuestToTransmission( - websocketpp::connection_hdl hdl, const std::string& transmission_id) { - if (transmission_guest_list_.find(transmission_id) != - transmission_guest_list_.end()) { - transmission_guest_list_[transmission_id].push_back(hdl); - } else { - std::vector guest_hdl_list; - guest_hdl_list.push_back(hdl); - transmission_guest_list_[transmission_id] = guest_hdl_list; - } - return true; -} +// bool TransmissionManager::BindGuestToTransmission( +// websocketpp::connection_hdl hdl, const std::string& transmission_id) { +// if (transmission_guest_list_.find(transmission_id) != +// transmission_guest_list_.end()) { +// transmission_guest_list_[transmission_id].push_back(hdl); +// } else { +// std::vector guest_hdl_list; +// guest_hdl_list.push_back(hdl); +// transmission_guest_list_[transmission_id] = guest_hdl_list; +// } +// return true; +// } -bool TransmissionManager::ReleaseHostFromTransmission( - websocketpp::connection_hdl hdl, const std::string& transmission_id) { - return true; -} +// bool TransmissionManager::ReleaseHostFromTransmission( +// websocketpp::connection_hdl hdl, const std::string& transmission_id) { +// return true; +// } -bool TransmissionManager::ReleaseGuestFromTransmission( - websocketpp::connection_hdl hdl, const std::string& transmission_id) { - return true; -} +// bool TransmissionManager::ReleaseGuestFromTransmission( +// websocketpp::connection_hdl hdl, const std::string& transmission_id) { +// return true; +// } -bool TransmissionManager::BindHostUsernameToWsHandle( - const std::string& host_username, websocketpp::connection_hdl hdl) { - if (transmission_host_username_list_.find(host_username) != - transmission_host_username_list_.end()) { - LOG_ERROR("Guest already bind to username [{}]", host_username.c_str()); - return false; - } else { - transmission_host_username_list_[host_username] = hdl; - } - return true; -} +// bool TransmissionManager::BindHostUsernameToWsHandle( +// websocketpp::connection_hdl hdl) { +// if (transmission_host_username_list_.find("host") != +// transmission_host_username_list_.end()) { +// LOG_ERROR("Host already exist"); +// return false; +// } else { +// transmission_host_username_list_["host"] = hdl; +// } +// return true; +// } -bool TransmissionManager::BindGuestUsernameToWsHandle( - const std::string& guest_username, websocketpp::connection_hdl hdl) { - if (transmission_guest_username_list_.find(guest_username) != - transmission_guest_username_list_.end()) { - LOG_ERROR("Guest already bind to username [{}]", guest_username.c_str()); - return false; - } else { - transmission_guest_username_list_[guest_username] = hdl; - } - return true; -} +// bool TransmissionManager::UpdateHostUsernameToWsHandle( +// const std::string& host_username, websocketpp::connection_hdl hdl) { +// if (transmission_host_username_list_.find("host") == +// transmission_host_username_list_.end()) { +// LOG_ERROR("Host not exist"); +// return false; +// } +// transmission_host_username_list_.erase("host"); +// transmission_host_username_list_[host_username] = hdl; -websocketpp::connection_hdl TransmissionManager::GetHostOfTransmission( - const std::string& transmission_id) { - if (transmission_host_list_.find(transmission_id) != - transmission_host_list_.end()) { - return transmission_host_list_[transmission_id]; - } else { - websocketpp::connection_hdl hdl; - return hdl; - } -} +// return true; +// } -std::string TransmissionManager::GetHostUsername( - websocketpp::connection_hdl hdl) { - for (auto host : transmission_host_username_list_) { - if (host.second.lock().get() == hdl.lock().get()) return host.first; - } +// bool TransmissionManager::BindGuestUsernameToWsHandle( +// const std::string& guest_username, websocketpp::connection_hdl hdl) { +// if (transmission_guest_username_list_.find(guest_username) != +// transmission_guest_username_list_.end()) { +// LOG_ERROR("Guest already bind to username [{}]", guest_username.c_str()); +// return false; +// } else { +// transmission_guest_username_list_[guest_username] = hdl; +// } +// return true; +// } - return ""; -} +// websocketpp::connection_hdl TransmissionManager::GetHostOfTransmission( +// const std::string& transmission_id) { +// if (transmission_host_list_.find(transmission_id) != +// transmission_host_list_.end()) { +// return transmission_host_list_[transmission_id]; +// } else { +// websocketpp::connection_hdl hdl; +// return hdl; +// } +// } -std::string TransmissionManager::GetGuestUsername( - websocketpp::connection_hdl hdl) { - for (auto guest : transmission_guest_username_list_) { - if (guest.second.lock().get() == hdl.lock().get()) return guest.first; - } +// std::string TransmissionManager::GetHostUsername( +// websocketpp::connection_hdl hdl) { +// for (auto host : transmission_host_username_list_) { +// if (host.second.lock().get() == hdl.lock().get()) return host.first; +// } - return ""; -} +// return ""; +// } + +// std::string TransmissionManager::GetGuestUsername( +// websocketpp::connection_hdl hdl) { +// for (auto guest : transmission_guest_username_list_) { +// if (guest.second.lock().get() == hdl.lock().get()) return guest.first; +// } + +// return ""; +// } std::vector TransmissionManager::GetAllGuestsOfTransmission( const std::string& transmission_id) { - if (transmission_guest_list_.find(transmission_id) != - transmission_guest_list_.end()) { - return transmission_guest_list_[transmission_id]; + if (transmission_user_ws_hdl_list_.find(transmission_id) != + transmission_user_ws_hdl_list_.end()) { + return transmission_user_ws_hdl_list_[transmission_id]; } else { return std::vector(); } @@ -121,12 +134,127 @@ std::vector TransmissionManager::GetAllMembersOfTransmission( const std::string& transmission_id) { std::vector member_list; - member_list.push_back( - GetHostUsername(GetHostOfTransmission(transmission_id))); - for (auto guest_hdl : GetAllGuestsOfTransmission(transmission_id)) { - member_list.push_back(GetGuestUsername(guest_hdl)); + member_list.push_back(GetUsername(guest_hdl)); } return member_list; +} + +bool TransmissionManager::BindWsHandleToTransmission( + websocketpp::connection_hdl hdl, const std::string& transmission_id) { + if (transmission_user_ws_hdl_list_.find(transmission_id) == + transmission_user_ws_hdl_list_.end()) { + transmission_user_ws_hdl_list_[transmission_id].push_back(hdl); + return true; + } else { + auto hdl_list = transmission_user_ws_hdl_list_[transmission_id]; + for (auto h : hdl_list) { + if (h.lock().get() == hdl.lock().get()) { + LOG_ERROR("Ws handle [{}] already bind to transmission [{}]", + hdl.lock().get(), transmission_id); + return false; + } + } + transmission_user_ws_hdl_list_[transmission_id].push_back(hdl); + } + return true; +} + +bool TransmissionManager::BindUserIdToTransmission( + const std::string& user_id, const std::string& transmission_id) { + if (transmission_user_id_list_.find(transmission_id) == + transmission_user_id_list_.end()) { + transmission_user_id_list_[transmission_id].push_back(user_id); + return true; + } else { + auto user_id_list = transmission_user_id_list_[transmission_id]; + for (auto id : user_id_list) { + if (id == user_id) { + LOG_ERROR("User id [{}] already bind to transmission [{}]", user_id, + transmission_id); + return false; + } + } + transmission_user_id_list_[transmission_id].push_back(user_id); + } + return true; +} + +bool TransmissionManager::BindUserIdToWsHandle( + const std::string& user_id, websocketpp::connection_hdl hdl) { + if (user_id_ws_hdl_list_.find(user_id) != user_id_ws_hdl_list_.end()) { + LOG_ERROR("User id already bind to websocket handle [{}]", user_id, + hdl.lock().get()); + return false; + } else { + user_id_ws_hdl_list_[user_id] = hdl; + } + return true; +} + +bool TransmissionManager::BindUserNameToUserId(const std::string& user_name, + const std::string& user_id) { + if (user_name_user_id_list_.find(user_id) == user_name_user_id_list_.end()) { + user_name_user_id_list_[user_id].push_back(user_name); + return true; + } else { + auto user_name_list = user_name_user_id_list_[user_id]; + for (auto name : user_name_list) { + if (name == user_name) { + LOG_ERROR("User name [{}] already bind to user id [{}]", user_name, + user_id); + return false; + } + } + user_name_user_id_list_[user_id].push_back(user_name); + } + return true; +} + +bool TransmissionManager::ReleaseWsHandleFromTransmission( + websocketpp::connection_hdl hdl, const std::string& transmission_id) { + return true; +} + +bool TransmissionManager::BindUsernameToWsHandle( + const std::string& username, websocketpp::connection_hdl hdl) { + if (username_ws_hdl_list_.find(username) != username_ws_hdl_list_.end()) { + LOG_ERROR("Guest already bind to username [{}]", username.c_str()); + return false; + } else { + username_ws_hdl_list_[username] = hdl; + } + return true; +} + +bool TransmissionManager::UpdateUsernameToWsHandle( + const std::string& username, websocketpp::connection_hdl hdl) { + if (username_ws_hdl_list_.find("host") == username_ws_hdl_list_.end()) { + LOG_ERROR("Host not exist"); + return false; + } + username_ws_hdl_list_.erase("host"); + username_ws_hdl_list_[username] = hdl; + + return true; +} + +std::string TransmissionManager::GetUsername(websocketpp::connection_hdl hdl) { + for (auto guest : username_ws_hdl_list_) { + if (guest.second.lock().get() == hdl.lock().get()) return guest.first; + } + + LOG_ERROR("No user with websocket handle [{}]", hdl.lock().get()); + return ""; +} + +websocketpp::connection_hdl TransmissionManager::GetWsHandle( + const std::string& username) { + if (username_ws_hdl_list_.find(username) != username_ws_hdl_list_.end()) { + return username_ws_hdl_list_[username]; + } else { + websocketpp::connection_hdl hdl; + return hdl; + } } \ No newline at end of file diff --git a/tests/signal_server/transmission_manager.h b/tests/signal_server/transmission_manager.h index 3a1bc18..e211683 100644 --- a/tests/signal_server/transmission_manager.h +++ b/tests/signal_server/transmission_manager.h @@ -11,22 +11,23 @@ class TransmissionManager { ~TransmissionManager(); public: - bool BindHostToTransmission(websocketpp::connection_hdl hdl, - const std::string& transmission_id); - bool BindGuestToTransmission(websocketpp::connection_hdl hdl, - const std::string& transmission_id); - bool ReleaseHostFromTransmission(websocketpp::connection_hdl hdl, - const std::string& transmission_id); - bool ReleaseGuestFromTransmission(websocketpp::connection_hdl hdl, - const std::string& transmission_id); + // bool BindHostToTransmission(websocketpp::connection_hdl hdl, + // const std::string& transmission_id); + // bool BindGuestToTransmission(websocketpp::connection_hdl hdl, + // const std::string& transmission_id); + // bool ReleaseHostFromTransmission(websocketpp::connection_hdl hdl, + // const std::string& transmission_id); + // bool ReleaseGuestFromTransmission(websocketpp::connection_hdl hdl, + // const std::string& transmission_id); - bool BindHostUsernameToWsHandle(const std::string& host_username, - websocketpp::connection_hdl hdl); - bool BindGuestUsernameToWsHandle(const std::string& guest_username, - websocketpp::connection_hdl hdl); + // bool BindHostUsernameToWsHandle(websocketpp::connection_hdl hdl); + // bool UpdateHostUsernameToWsHandle(const std::string& host_username, + // websocketpp::connection_hdl hdl); + // bool BindGuestUsernameToWsHandle(const std::string& guest_username, + // websocketpp::connection_hdl hdl); - std::string GetHostUsername(websocketpp::connection_hdl hdl); - std::string GetGuestUsername(websocketpp::connection_hdl hdl); + // std::string GetHostUsername(websocketpp::connection_hdl hdl); + // std::string GetGuestUsername(websocketpp::connection_hdl hdl); websocketpp::connection_hdl GetHostOfTransmission( const std::string& transmission_id); @@ -38,6 +39,25 @@ class TransmissionManager { std::vector GetAllMembersOfTransmission( const std::string& transmission_id); + public: + bool BindWsHandleToTransmission(websocketpp::connection_hdl hdl, + const std::string& transmission_id); + bool BindUserIdToTransmission(const std::string& user_id, + const std::string& transmission_id); + bool BindUserIdToWsHandle(const std::string& user_id, + websocketpp::connection_hdl hdl); + bool BindUserNameToUserId(const std::string& user_name, + const std::string& user_id); + + bool ReleaseWsHandleFromTransmission(websocketpp::connection_hdl hdl, + const std::string& transmission_id); + bool BindUsernameToWsHandle(const std::string& username, + websocketpp::connection_hdl hdl); + bool UpdateUsernameToWsHandle(const std::string& username, + websocketpp::connection_hdl hdl); + std::string GetUsername(websocketpp::connection_hdl hdl); + websocketpp::connection_hdl GetWsHandle(const std::string& username); + private: std::map transmission_host_list_; std::map> @@ -47,6 +67,15 @@ class TransmissionManager { transmission_host_username_list_; std::map transmission_guest_username_list_; + + private: + std::map> + transmission_user_ws_hdl_list_; + std::map> transmission_user_id_list_; + std::map user_id_ws_hdl_list_; + std::map> user_name_user_id_list_; + + std::map username_ws_hdl_list_; }; #endif \ No newline at end of file diff --git a/thirdparty/websocketpp/cmake/websocketpp-config.cmake b/thirdparty/websocketpp/cmake/websocketpp-config.cmake index 4d920bc..90930ca 100644 --- a/thirdparty/websocketpp/cmake/websocketpp-config.cmake +++ b/thirdparty/websocketpp/cmake/websocketpp-config.cmake @@ -1,28 +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() +# - 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() diff --git a/thirdparty/websocketpp/cmake/websocketpp-configVersion.cmake b/thirdparty/websocketpp/cmake/websocketpp-configVersion.cmake index 6ae43cf..a93d5b1 100644 --- a/thirdparty/websocketpp/cmake/websocketpp-configVersion.cmake +++ b/thirdparty/websocketpp/cmake/websocketpp-configVersion.cmake @@ -1,88 +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() +# 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() diff --git a/thirdparty/websocketpp/include/websocketpp/base64/base64.hpp b/thirdparty/websocketpp/include/websocketpp/base64/base64.hpp index fbc5841..ff1561d 100644 --- a/thirdparty/websocketpp/include/websocketpp/base64/base64.hpp +++ b/thirdparty/websocketpp/include/websocketpp/base64/base64.hpp @@ -1,178 +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 - -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(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(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(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(char_array_3[j]); - } - } - - return ret; -} - -} // namespace websocketpp - -#endif // _BASE64_HPP_ +/* + ****** + base64.hpp is a repackaging of the base64.cpp and base64.h files into a + single header suitable for use as a header only library. This conversion was + done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to + the code are redistributed under the same license as the original, which is + listed below. + ****** + + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#ifndef _BASE64_HPP_ +#define _BASE64_HPP_ + +#include + +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(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(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(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(char_array_3[j]); + } + } + + return ret; +} + +} // namespace websocketpp + +#endif // _BASE64_HPP_ diff --git a/thirdparty/websocketpp/include/websocketpp/client.hpp b/thirdparty/websocketpp/include/websocketpp/client.hpp index 3585e27..8782d7e 100644 --- a/thirdparty/websocketpp/include/websocketpp/client.hpp +++ b/thirdparty/websocketpp/include/websocketpp/client.hpp @@ -1,33 +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 - -#endif //WEBSOCKETPP_CLIENT_HPP +/* + * 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 + +#endif //WEBSOCKETPP_CLIENT_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/close.hpp b/thirdparty/websocketpp/include/websocketpp/close.hpp index 77b31b0..276498e 100644 --- a/thirdparty/websocketpp/include/websocketpp/close.hpp +++ b/thirdparty/websocketpp/include/websocketpp/close.hpp @@ -1,353 +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 -#include -#include -#include - -#include - -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 + +/* + * 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 +#include +#include +#include + +#include + +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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/asio.hpp b/thirdparty/websocketpp/include/websocketpp/common/asio.hpp index 9ca25f1..3c8fa13 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/asio.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/asio.hpp @@ -1,141 +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 - - #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 - #include - #include -#else - #include - - // 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 - #include - #endif - - #include - #include -#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 - 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 - 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 - 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 +/* + * 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 + + #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 + #include + #include +#else + #include + + // 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 + #include + #endif + + #include + #include +#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 + 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 + 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 + 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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/asio_ssl.hpp b/thirdparty/websocketpp/include/websocketpp/common/asio_ssl.hpp index ee1f4ee..6989283 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/asio_ssl.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/asio_ssl.hpp @@ -1,39 +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 -#else - #include -#endif - -#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP +/* + * 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 +#else + #include +#endif + +#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/common/chrono.hpp b/thirdparty/websocketpp/include/websocketpp/common/chrono.hpp index 7ac6944..975ee04 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/chrono.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/chrono.hpp @@ -1,68 +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 - -// 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 -#else - #include -#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 +/* + * 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 + +// 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 +#else + #include +#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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/connection_hdl.hpp b/thirdparty/websocketpp/include/websocketpp/common/connection_hdl.hpp index 3e1944b..1044c88 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/connection_hdl.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/connection_hdl.hpp @@ -1,52 +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 - -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 connection_hdl; - -} // namespace websocketpp - -#endif // WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP +/* + * 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 + +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 connection_hdl; + +} // namespace websocketpp + +#endif // WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/common/cpp11.hpp b/thirdparty/websocketpp/include/websocketpp/common/cpp11.hpp index 745ff6a..492a3b8 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/cpp11.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/cpp11.hpp @@ -1,162 +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 +/* + * 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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/functional.hpp b/thirdparty/websocketpp/include/websocketpp/common/functional.hpp index bd8c9fc..d332dd1 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/functional.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/functional.hpp @@ -1,105 +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 - -// 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 -#else - #include - #include - #include -#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 - 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 - void clear_function(T & x) { - x.clear(); - } -#endif - -} // namespace lib -} // namespace websocketpp - -#endif // WEBSOCKETPP_COMMON_FUNCTIONAL_HPP +/* + * 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 + +// 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 +#else + #include + #include + #include +#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 + 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 + void clear_function(T & x) { + x.clear(); + } +#endif + +} // namespace lib +} // namespace websocketpp + +#endif // WEBSOCKETPP_COMMON_FUNCTIONAL_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/common/md5.hpp b/thirdparty/websocketpp/include/websocketpp/common/md5.hpp index 9850393..279725f 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/md5.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/md5.hpp @@ -1,448 +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 - . 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 . - 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 -#include -#include - -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(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 +/* + 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 + . 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 . + 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 +#include +#include + +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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/memory.hpp b/thirdparty/websocketpp/include/websocketpp/common/memory.hpp index 3df14a6..42048e3 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/memory.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/memory.hpp @@ -1,88 +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 - -// 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 -#else - #include - #include - #include - #include - #include -#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 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 unique_ptr_uchar_array; -#endif - -} // namespace lib -} // namespace websocketpp - -#endif // WEBSOCKETPP_COMMON_MEMORY_HPP +/* + * 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 + +// 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 +#else + #include + #include + #include + #include + #include +#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 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 unique_ptr_uchar_array; +#endif + +} // namespace lib +} // namespace websocketpp + +#endif // WEBSOCKETPP_COMMON_MEMORY_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/common/network.hpp b/thirdparty/websocketpp/include/websocketpp/common/network.hpp index fd9dc6c..26a4cb9 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/network.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/network.hpp @@ -1,106 +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 -#else - //#include - #include -#endif - -#include - -namespace websocketpp { -namespace lib { -namespace net { - -inline bool is_little_endian() { - short int val = 0x1; - char *ptr = reinterpret_cast(&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 +/* + * 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 +#else + //#include + #include +#endif + +#include + +namespace websocketpp { +namespace lib { +namespace net { + +inline bool is_little_endian() { + short int val = 0x1; + char *ptr = reinterpret_cast(&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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/platforms.hpp b/thirdparty/websocketpp/include/websocketpp/common/platforms.hpp index d4e3964..8779857 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/platforms.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/platforms.hpp @@ -1,46 +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 +/* + * 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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/random.hpp b/thirdparty/websocketpp/include/websocketpp/common/random.hpp index 3ef701c..ddf9969 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/random.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/random.hpp @@ -1,82 +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 - -// 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 -#else - #include - - #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 46 - #include - #include - #elif (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) >= 43 - #include - #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 +/* + * 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 + +// 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 +#else + #include + + #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 46 + #include + #include + #elif (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) >= 43 + #include + #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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/regex.hpp b/thirdparty/websocketpp/include/websocketpp/common/regex.hpp index 2d4a50c..326635d 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/regex.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/regex.hpp @@ -1,59 +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 -#else - #include -#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 +/* + * 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 +#else + #include +#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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/stdint.hpp b/thirdparty/websocketpp/include/websocketpp/common/stdint.hpp index 25790c6..ec48ea7 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/stdint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/stdint.hpp @@ -1,73 +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 - - 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 -#endif - -#endif // WEBSOCKETPP_COMMON_STDINT_HPP +/* + * 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 + + 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 +#endif + +#endif // WEBSOCKETPP_COMMON_STDINT_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/common/system_error.hpp b/thirdparty/websocketpp/include/websocketpp/common/system_error.hpp index 3cfcf14..e5aea25 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/system_error.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/system_error.hpp @@ -1,84 +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 - -// 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 -#else - #include - #include -#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 +/* + * 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 + +// 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 +#else + #include + #include +#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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/thread.hpp b/thirdparty/websocketpp/include/websocketpp/common/thread.hpp index bf0c92c..1b0472a 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/thread.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/thread.hpp @@ -1,88 +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 - -// 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 and -#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 - #include - #include -#elif defined(_WEBSOCKETPP_CPP11_THREAD_) - #include - #include - #include -#else - #include - #include - #include -#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 +/* + * 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 + +// 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 and +#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 + #include + #include +#elif defined(_WEBSOCKETPP_CPP11_THREAD_) + #include + #include + #include +#else + #include + #include + #include +#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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/time.hpp b/thirdparty/websocketpp/include/websocketpp/common/time.hpp index a53d86f..571688e 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/time.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/time.hpp @@ -1,56 +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 - -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 +/* + * 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 + +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 diff --git a/thirdparty/websocketpp/include/websocketpp/common/type_traits.hpp b/thirdparty/websocketpp/include/websocketpp/common/type_traits.hpp index 1abc33b..c89b82b 100644 --- a/thirdparty/websocketpp/include/websocketpp/common/type_traits.hpp +++ b/thirdparty/websocketpp/include/websocketpp/common/type_traits.hpp @@ -1,65 +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 - -// 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 -#else - #include -#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 +/* + * 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 + +// 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 +#else + #include +#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 diff --git a/thirdparty/websocketpp/include/websocketpp/concurrency/basic.hpp b/thirdparty/websocketpp/include/websocketpp/concurrency/basic.hpp index e4a146b..1943ad7 100644 --- a/thirdparty/websocketpp/include/websocketpp/concurrency/basic.hpp +++ b/thirdparty/websocketpp/include/websocketpp/concurrency/basic.hpp @@ -1,46 +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 - -namespace websocketpp { -namespace concurrency { - -/// Concurrency policy that uses std::mutex / boost::mutex -class basic { -public: - typedef lib::mutex mutex_type; - typedef lib::lock_guard scoped_lock_type; -}; - -} // namespace concurrency -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP +/* + * 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 + +namespace websocketpp { +namespace concurrency { + +/// Concurrency policy that uses std::mutex / boost::mutex +class basic { +public: + typedef lib::mutex mutex_type; + typedef lib::lock_guard scoped_lock_type; +}; + +} // namespace concurrency +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/concurrency/none.hpp b/thirdparty/websocketpp/include/websocketpp/concurrency/none.hpp index 2200a22..da9aa41 100644 --- a/thirdparty/websocketpp/include/websocketpp/concurrency/none.hpp +++ b/thirdparty/websocketpp/include/websocketpp/concurrency/none.hpp @@ -1,80 +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 +/* + * 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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/asio.hpp b/thirdparty/websocketpp/include/websocketpp/config/asio.hpp index ae7e303..d28d0fb 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/asio.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/asio.hpp @@ -1,77 +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 -#include -#include - -// Pull in non-tls config -#include - -// 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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_HPP +/* + * 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 +#include +#include + +// Pull in non-tls config +#include + +// 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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/asio_client.hpp b/thirdparty/websocketpp/include/websocketpp/config/asio_client.hpp index 32a5425..1cb594d 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/asio_client.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/asio_client.hpp @@ -1,77 +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 -#include -#include - -// Pull in non-tls config -#include - -// 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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP +/* + * 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 +#include +#include + +// Pull in non-tls config +#include + +// 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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls.hpp b/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls.hpp index 4fc8588..6c1357f 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls.hpp @@ -1,73 +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 -#include - -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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_HPP +/* + * 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 +#include + +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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls_client.hpp b/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls_client.hpp index 31d66b7..6e3f7ba 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls_client.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/asio_no_tls_client.hpp @@ -1,73 +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 -#include - -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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP +/* + * 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 +#include + +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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/boost_config.hpp b/thirdparty/websocketpp/include/websocketpp/config/boost_config.hpp index b199f13..57671cc 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/boost_config.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/boost_config.hpp @@ -1,72 +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 - -// _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 +/* + * 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 + +// _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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/core.hpp b/thirdparty/websocketpp/include/websocketpp/config/core.hpp index 5f1160e..93981aa 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/core.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/core.hpp @@ -1,297 +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 -#include -#include - -// Concurrency -#include - -// Transport -#include - -// HTTP -#include -#include - -// Messages -#include -#include - -// Loggers -#include -#include - -// RNG -#include - -// User stub base classes -#include -#include - -// Extensions -#include - -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_type; - typedef message_buffer::alloc::con_msg_manager - con_msg_manager_type; - typedef message_buffer::alloc::endpoint_msg_manager - endpoint_msg_manager_type; - - /// Logging policies - typedef websocketpp::log::basic elog_type; - typedef websocketpp::log::basic alog_type; - - /// RNG policies - typedef websocketpp::random::none::int_generator 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_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_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 +/* + * 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 +#include +#include + +// Concurrency +#include + +// Transport +#include + +// HTTP +#include +#include + +// Messages +#include +#include + +// Loggers +#include +#include + +// RNG +#include + +// User stub base classes +#include +#include + +// Extensions +#include + +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_type; + typedef message_buffer::alloc::con_msg_manager + con_msg_manager_type; + typedef message_buffer::alloc::endpoint_msg_manager + endpoint_msg_manager_type; + + /// Logging policies + typedef websocketpp::log::basic elog_type; + typedef websocketpp::log::basic alog_type; + + /// RNG policies + typedef websocketpp::random::none::int_generator 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_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_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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/core_client.hpp b/thirdparty/websocketpp/include/websocketpp/config/core_client.hpp index 5854e04..dadf8a4 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/core_client.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/core_client.hpp @@ -1,294 +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 -#include -#include - -// Concurrency -#ifndef _WEBSOCKETPP_NO_THREADING_ -#include -#else -#include -#endif - -// Transport -#include - -// HTTP -#include -#include - -// Messages -#include -#include - -// Loggers -#include - -// RNG -#include - -// User stub base classes -#include -#include - -// Extensions -#include - -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_type; - typedef message_buffer::alloc::con_msg_manager - con_msg_manager_type; - typedef message_buffer::alloc::endpoint_msg_manager - endpoint_msg_manager_type; - - /// Logging policies - typedef websocketpp::log::basic elog_type; - typedef websocketpp::log::basic alog_type; - - /// RNG policies - typedef websocketpp::random::random_device::int_generator 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_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_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 +/* + * 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 +#include +#include + +// Concurrency +#ifndef _WEBSOCKETPP_NO_THREADING_ +#include +#else +#include +#endif + +// Transport +#include + +// HTTP +#include +#include + +// Messages +#include +#include + +// Loggers +#include + +// RNG +#include + +// User stub base classes +#include +#include + +// Extensions +#include + +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_type; + typedef message_buffer::alloc::con_msg_manager + con_msg_manager_type; + typedef message_buffer::alloc::endpoint_msg_manager + endpoint_msg_manager_type; + + /// Logging policies + typedef websocketpp::log::basic elog_type; + typedef websocketpp::log::basic alog_type; + + /// RNG policies + typedef websocketpp::random::random_device::int_generator 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_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_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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/debug.hpp b/thirdparty/websocketpp/include/websocketpp/config/debug.hpp index ce75b5c..223f72f 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/debug.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/debug.hpp @@ -1,286 +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 -#include - -// Concurrency -#include - -// Transport -#include - -// HTTP -#include -#include - -// Messages -#include -#include - -// Loggers -#include - -// RNG -#include - -// User stub base classes -#include -#include - -// Extensions -#include - -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_type; - typedef message_buffer::alloc::con_msg_manager - con_msg_manager_type; - typedef message_buffer::alloc::endpoint_msg_manager - endpoint_msg_manager_type; - - /// Logging policies - typedef websocketpp::log::basic elog_type; - typedef websocketpp::log::basic alog_type; - - /// RNG policies - typedef websocketpp::random::none::int_generator 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_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_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 +/* + * 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 +#include + +// Concurrency +#include + +// Transport +#include + +// HTTP +#include +#include + +// Messages +#include +#include + +// Loggers +#include + +// RNG +#include + +// User stub base classes +#include +#include + +// Extensions +#include + +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_type; + typedef message_buffer::alloc::con_msg_manager + con_msg_manager_type; + typedef message_buffer::alloc::endpoint_msg_manager + endpoint_msg_manager_type; + + /// Logging policies + typedef websocketpp::log::basic elog_type; + typedef websocketpp::log::basic alog_type; + + /// RNG policies + typedef websocketpp::random::none::int_generator 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_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_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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/debug_asio.hpp b/thirdparty/websocketpp/include/websocketpp/config/debug_asio.hpp index 4b7bf86..a57c736 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/debug_asio.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/debug_asio.hpp @@ -1,77 +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 -#include -#include - -// Pull in non-tls config -#include - -// 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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP +/* + * 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 +#include +#include + +// Pull in non-tls config +#include + +// 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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/debug_asio_no_tls.hpp b/thirdparty/websocketpp/include/websocketpp/config/debug_asio_no_tls.hpp index de595f6..b3dc83b 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/debug_asio_no_tls.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/debug_asio_no_tls.hpp @@ -1,73 +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 -#include - -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_type; -}; - -} // namespace config -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP +/* + * 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 +#include + +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_type; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/config/minimal_client.hpp b/thirdparty/websocketpp/include/websocketpp/config/minimal_client.hpp index eec6575..72528cd 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/minimal_client.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/minimal_client.hpp @@ -1,72 +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 - -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: - * - * - * - * - * - * - * C++11 STL or Boost - * - * - * - * - * Operating System: - * or - * or (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 +/* + * 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 + +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: + * + * + * + * + * + * + * C++11 STL or Boost + * + * + * + * + * Operating System: + * or + * or (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 diff --git a/thirdparty/websocketpp/include/websocketpp/config/minimal_server.hpp b/thirdparty/websocketpp/include/websocketpp/config/minimal_server.hpp index ae5d0e8..dd1aedb 100644 --- a/thirdparty/websocketpp/include/websocketpp/config/minimal_server.hpp +++ b/thirdparty/websocketpp/include/websocketpp/config/minimal_server.hpp @@ -1,312 +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 -#include -#include - -// Concurrency -#include - -// Transport -#include - -// HTTP -#include -#include - -// Messages -#include -#include - -// Loggers -#include - -// RNG -#include - -// User stub base classes -#include -#include - -// Extensions -#include - -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: - * - * - * - * - * - * - * C++11 STL or Boost - * - * - * - * - * Operating System: - * or - * or (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_type; - typedef message_buffer::alloc::con_msg_manager - con_msg_manager_type; - typedef message_buffer::alloc::endpoint_msg_manager - 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 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_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_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 +/* + * 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 +#include +#include + +// Concurrency +#include + +// Transport +#include + +// HTTP +#include +#include + +// Messages +#include +#include + +// Loggers +#include + +// RNG +#include + +// User stub base classes +#include +#include + +// Extensions +#include + +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: + * + * + * + * + * + * + * C++11 STL or Boost + * + * + * + * + * Operating System: + * or + * or (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_type; + typedef message_buffer::alloc::con_msg_manager + con_msg_manager_type; + typedef message_buffer::alloc::endpoint_msg_manager + 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 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_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_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 diff --git a/thirdparty/websocketpp/include/websocketpp/connection.hpp b/thirdparty/websocketpp/include/websocketpp/connection.hpp index 4a5532d..d019fce 100644 --- a/thirdparty/websocketpp/include/websocketpp/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/connection.hpp @@ -1,1642 +1,1642 @@ -/* - * 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_HPP -#define WEBSOCKETPP_CONNECTION_HPP - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace websocketpp { - -/// The type and function signature of an open handler -/** - * The open handler is called once for every successful WebSocket connection - * attempt. Either the fail handler or the open handler will be called for each - * WebSocket connection attempt. HTTP Connections that did not attempt to - * upgrade the connection to the WebSocket protocol will trigger the http - * handler instead of fail/open. - */ -typedef lib::function open_handler; - -/// The type and function signature of a close handler -/** - * The close handler is called once for every successfully established - * connection after it is no longer capable of sending or receiving new messages - * - * The close handler will be called exactly once for every connection for which - * the open handler was called. - */ -typedef lib::function close_handler; - -/// The type and function signature of a fail handler -/** - * The fail handler is called once for every unsuccessful WebSocket connection - * attempt. Either the fail handler or the open handler will be called for each - * WebSocket connection attempt. HTTP Connections that did not attempt to - * upgrade the connection to the WebSocket protocol will trigger the http - * handler instead of fail/open. - */ -typedef lib::function fail_handler; - -/// The type and function signature of an interrupt handler -/** - * The interrupt handler is called when a connection receives an interrupt - * request from the application. Interrupts allow the application to trigger a - * handler to be run in the absense of a WebSocket level handler trigger (like - * a new message). - * - * This is typically used by another application thread to schedule some tasks - * that can only be run from within the handler chain for thread safety reasons. - */ -typedef lib::function interrupt_handler; - -/// The type and function signature of a ping handler -/** - * The ping handler is called when the connection receives a WebSocket ping - * control frame. The string argument contains the ping payload. The payload is - * a binary string up to 126 bytes in length. The ping handler returns a bool, - * true if a pong response should be sent, false if the pong response should be - * suppressed. - */ -typedef lib::function ping_handler; - -/// The type and function signature of a pong handler -/** - * The pong handler is called when the connection receives a WebSocket pong - * control frame. The string argument contains the pong payload. The payload is - * a binary string up to 126 bytes in length. - */ -typedef lib::function pong_handler; - -/// The type and function signature of a pong timeout handler -/** - * The pong timeout handler is called when a ping goes unanswered by a pong for - * longer than the locally specified timeout period. - */ -typedef lib::function pong_timeout_handler; - -/// The type and function signature of a validate handler -/** - * The validate handler is called after a WebSocket handshake has been received - * and processed but before it has been accepted. This gives the application a - * chance to implement connection details specific policies for accepting - * connections and the ability to negotiate extensions and subprotocols. - * - * The validate handler return value indicates whether or not the connection - * should be accepted. Additional methods may be called during the function to - * set response headers, set HTTP return/error codes, etc. - */ -typedef lib::function validate_handler; - -/// The type and function signature of a http handler -/** - * The http handler is called when an HTTP connection is made that does not - * attempt to upgrade the connection to the WebSocket protocol. This allows - * WebSocket++ servers to respond to these requests with regular HTTP responses. - * - * This can be used to deliver error pages & dashboards and to deliver static - * files such as the base HTML & JavaScript for an otherwise single page - * WebSocket application. - * - * Note: WebSocket++ is designed to be a high performance WebSocket server. It - * is not tuned to provide a full featured, high performance, HTTP web server - * solution. The HTTP handler is appropriate only for low volume HTTP traffic. - * If you expect to serve high volumes of HTTP traffic a dedicated HTTP web - * server is strongly recommended. - * - * The default HTTP handler will return a 426 Upgrade Required error. Custom - * handlers may override the response status code to deliver any type of - * response. - */ -typedef lib::function http_handler; - -// -typedef lib::function read_handler; -typedef lib::function write_frame_handler; - -// constants related to the default WebSocket protocol versions available -#ifdef _WEBSOCKETPP_INITIALIZER_LISTS_ // simplified C++11 version - /// Container that stores the list of protocol versions supported - /** - * @todo Move this to configs to allow compile/runtime disabling or enabling - * of protocol versions - */ - static std::vector const versions_supported = {0,7,8,13}; -#else - /// Helper array to get around lack of initializer lists pre C++11 - static int const helper[] = {0,7,8,13}; - /// Container that stores the list of protocol versions supported - /** - * @todo Move this to configs to allow compile/runtime disabling or enabling - * of protocol versions - */ - static std::vector const versions_supported(helper,helper+4); -#endif - -namespace session { -namespace state { - // externally visible session state (states based on the RFC) - enum value { - connecting = 0, - open = 1, - closing = 2, - closed = 3 - }; -} // namespace state - - -namespace fail { -namespace status { - enum value { - GOOD = 0, // no failure yet! - SYSTEM = 1, // system call returned error, check that code - WEBSOCKET = 2, // websocket close codes contain error - UNKNOWN = 3, // No failure information is available - TIMEOUT_TLS = 4, // TLS handshake timed out - TIMEOUT_WS = 5 // WS handshake timed out - }; -} // namespace status -} // namespace fail - -namespace internal_state { - // More granular internal states. These are used for multi-threaded - // connection synchronization and preventing values that are not yet or no - // longer available from being used. - - enum value { - USER_INIT = 0, - TRANSPORT_INIT = 1, - READ_HTTP_REQUEST = 2, - WRITE_HTTP_REQUEST = 3, - READ_HTTP_RESPONSE = 4, - WRITE_HTTP_RESPONSE = 5, - PROCESS_HTTP_REQUEST = 6, - PROCESS_CONNECTION = 7 - }; -} // namespace internal_state - - -namespace http_state { - // states to keep track of the progress of http connections - - enum value { - init = 0, - deferred = 1, - headers_written = 2, - body_written = 3, - closed = 4 - }; -} // namespace http_state - -} // namespace session - -/// Represents an individual WebSocket connection -template -class connection - : public config::transport_type::transport_con_type - , public config::connection_base -{ -public: - /// Type of this connection - typedef connection type; - /// Type of a shared pointer to this connection - typedef lib::shared_ptr ptr; - /// Type of a weak pointer to this connection - typedef lib::weak_ptr weak_ptr; - - /// Type of the concurrency component of this connection - typedef typename config::concurrency_type concurrency_type; - /// Type of the access logging policy - typedef typename config::alog_type alog_type; - /// Type of the error logging policy - typedef typename config::elog_type elog_type; - - /// Type of the transport component of this connection - typedef typename config::transport_type::transport_con_type - transport_con_type; - /// Type of a shared pointer to the transport component of this connection - typedef typename transport_con_type::ptr transport_con_ptr; - - typedef lib::function termination_handler; - - typedef typename concurrency_type::scoped_lock_type scoped_lock_type; - typedef typename concurrency_type::mutex_type mutex_type; - - 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 con_msg_manager_type; - typedef typename con_msg_manager_type::ptr con_msg_manager_ptr; - - /// Type of RNG - typedef typename config::rng_type rng_type; - - typedef processor::processor processor_type; - typedef lib::shared_ptr processor_ptr; - - // Message handler (needs to know message type) - typedef lib::function message_handler; - - /// Type of a pointer to a transport timer handle - typedef typename transport_con_type::timer_ptr timer_ptr; - - // Misc Convenience Types - typedef session::internal_state::value istate_type; - -private: - enum terminate_status { - failed = 1, - closed, - unknown - }; -public: - - explicit connection(bool p_is_server, std::string const & ua, const lib::shared_ptr& alog, - const lib::shared_ptr& elog, rng_type & rng) - : transport_con_type(p_is_server, alog, elog) - , m_handle_read_frame(lib::bind( - &type::handle_read_frame, - this, - lib::placeholders::_1, - lib::placeholders::_2 - )) - , m_write_frame_handler(lib::bind( - &type::handle_write_frame, - this, - lib::placeholders::_1 - )) - , m_user_agent(ua) - , 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_state(session::state::connecting) - , m_internal_state(session::internal_state::USER_INIT) - , m_msg_manager(new con_msg_manager_type()) - , m_send_buffer_size(0) - , m_write_flag(false) - , m_read_flag(true) - , m_is_server(p_is_server) - , m_alog(alog) - , m_elog(elog) - , m_rng(rng) - , m_local_close_code(close::status::abnormal_close) - , m_remote_close_code(close::status::abnormal_close) - , m_is_http(false) - , m_http_state(session::http_state::init) - , m_was_clean(false) - { - m_alog->write(log::alevel::devel,"connection constructor"); - } - - /// Get a shared pointer to this component - ptr get_shared() { - return lib::static_pointer_cast(transport_con_type::get_shared()); - } - - /////////////////////////// - // Set Handler Callbacks // - /////////////////////////// - - /// Set open handler - /** - * The open handler is called after the WebSocket handshake is complete and - * the connection is considered OPEN. - * - * @param h The new open_handler - */ - void set_open_handler(open_handler h) { - m_open_handler = h; - } - - /// Set close handler - /** - * The close handler is called immediately after the connection is closed. - * - * @param h The new close_handler - */ - void set_close_handler(close_handler h) { - m_close_handler = h; - } - - /// Set fail handler - /** - * The fail handler is called whenever the connection fails while the - * handshake is bring processed. - * - * @param h The new fail_handler - */ - void set_fail_handler(fail_handler h) { - m_fail_handler = h; - } - - /// Set ping handler - /** - * The ping handler is called whenever the connection receives a ping - * control frame. The ping payload is included. - * - * The ping handler's return time controls whether or not a pong is - * sent in response to this ping. Returning false will suppress the - * return pong. If no ping handler is set a pong will be sent. - * - * @param h The new ping_handler - */ - void set_ping_handler(ping_handler h) { - m_ping_handler = h; - } - - /// Set pong handler - /** - * The pong handler is called whenever the connection receives a pong - * control frame. The pong payload is included. - * - * @param h The new pong_handler - */ - void set_pong_handler(pong_handler h) { - m_pong_handler = h; - } - - /// Set pong timeout handler - /** - * If the transport component being used supports timers, the pong timeout - * handler is called whenever a pong control frame is not received with the - * configured timeout period after the application sends a ping. - * - * The config setting `timeout_pong` controls the length of the timeout - * period. It is specified in milliseconds. - * - * This can be used to probe the health of the remote endpoint's WebSocket - * implementation. This does not guarantee that the remote application - * itself is still healthy but can be a useful diagnostic. - * - * Note: receipt of this callback doesn't mean the pong will never come. - * This functionality will not suppress delivery of the pong in question - * should it arrive after the timeout. - * - * @param h The new pong_timeout_handler - */ - void set_pong_timeout_handler(pong_timeout_handler h) { - m_pong_timeout_handler = h; - } - - /// Set interrupt handler - /** - * The interrupt handler is called whenever the connection is manually - * interrupted by the application. - * - * @param h The new interrupt_handler - */ - void set_interrupt_handler(interrupt_handler h) { - m_interrupt_handler = h; - } - - /// Set http handler - /** - * The http handler is called after an HTTP request other than a WebSocket - * upgrade request is received. It allows a WebSocket++ server to respond - * to regular HTTP requests on the same port as it processes WebSocket - * connections. This can be useful for hosting error messages, flash - * policy files, status pages, and other simple HTTP responses. It is not - * intended to be used as a primary web server. - * - * @param h The new http_handler - */ - void set_http_handler(http_handler h) { - m_http_handler = h; - } - - /// Set validate handler - /** - * The validate handler is called after a WebSocket handshake has been - * parsed but before a response is returned. It provides the application - * a chance to examine the request and determine whether or not it wants - * to accept the connection. - * - * Returning false from the validate handler will reject the connection. - * If no validate handler is present, all connections will be allowed. - * - * @param h The new validate_handler - */ - void set_validate_handler(validate_handler h) { - m_validate_handler = h; - } - - /// Set message handler - /** - * The message handler is called after a new message has been received. - * - * @param h The new message_handler - */ - void set_message_handler(message_handler h) { - 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) { - 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) { - 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) { - m_pong_timeout_dur = dur; - } - - /// Get maximum message size - /** - * Get maximum message size. Maximum message size determines the point at - * which the connection will fail with the message_too_big protocol error. - * - * The default is set by the endpoint that creates the connection. - * - * @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 connection will fail with the message_too_big protocol error. - * This value may be changed during the connection. - * - * The default is set by the endpoint that creates the connection. - * - * @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; - if (m_processor) { - m_processor->set_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 endpoint that creates the connection. - * - * @since 0.5.0 - * - * @return The maximum HTTP message body size - */ - size_t get_max_http_body_size() const { - return m_request.get_max_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 endpoint that creates the connection. - * - * @since 0.5.0 - * - * @param new_value The value to set as the maximum message size. - */ - void set_max_http_body_size(size_t new_value) { - m_request.set_max_body_size(new_value); - } - - ////////////////////////////////// - // Uncategorized public methods // - ////////////////////////////////// - - /// Get the size of the outgoing write buffer (in payload bytes) - /** - * Retrieves the number of bytes in the outgoing write buffer that have not - * already been dispatched to the transport layer. This represents the bytes - * that are presently cancelable without uncleanly ending the websocket - * connection - * - * This method invokes the m_write_lock mutex - * - * @return The current number of bytes in the outgoing send buffer. - */ - size_t get_buffered_amount() const; - - /// Get the size of the outgoing write buffer (in payload bytes) - /** - * @deprecated use `get_buffered_amount` instead - */ - size_t buffered_amount() const { - return get_buffered_amount(); - } - - //////////////////// - // Action Methods // - //////////////////// - - /// Create a message and then add it to the outgoing send queue - /** - * Convenience method to send a message given a payload string and - * optionally an opcode. Default opcode is utf8 text. - * - * This method locks the m_write_lock mutex - * - * @param payload The payload string to generated the message with - * - * @param op The opcode to generated the message with. Default is - * frame::opcode::text - */ - lib::error_code send(std::string const & payload, frame::opcode::value op = - frame::opcode::text); - - /// Send a message (raw array overload) - /** - * Convenience method to send a message given a raw array and optionally an - * opcode. Default opcode is binary. - * - * This method locks the m_write_lock mutex - * - * @param payload A pointer to the array containing the bytes to send. - * - * @param len Length of the array. - * - * @param op The opcode to generated the message with. Default is - * frame::opcode::binary - */ - lib::error_code send(void const * payload, size_t len, frame::opcode::value - op = frame::opcode::binary); - - /// Add a message to the outgoing send queue - /** - * If presented with a prepared message it is added without validation or - * framing. If presented with an unprepared message it is validated, framed, - * and then added - * - * Errors are returned via an exception - * \todo make exception system_error rather than error_code - * - * This method invokes the m_write_lock mutex - * - * @param msg A message_ptr to the message to send. - */ - lib::error_code send(message_ptr msg); - - /// Asyncronously invoke handler::on_inturrupt - /** - * Signals to the connection to asyncronously invoke the on_inturrupt - * callback for this connection's handler once it is safe to do so. - * - * When the on_inturrupt handler callback is called it will be from - * within the transport event loop with all the thread safety features - * guaranteed by the transport to regular handlers - * - * Multiple inturrupt signals can be active at once on the same connection - * - * @return An error code - */ - lib::error_code interrupt(); - - /// Transport inturrupt callback - void handle_interrupt(); - - /// Pause reading of new data - /** - * 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. - */ - lib::error_code pause_reading(); - - /// Pause reading callback - void handle_pause_reading(); - - /// Resume reading of new data - /** - * 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. - */ - lib::error_code resume_reading(); - - /// Resume reading callback - void handle_resume_reading(); - - /// Send a ping - /** - * Initiates a ping with the given payload/ - * - * There is no feedback directly from ping except in cases of immediately - * detectable errors. Feedback will be provided via on_pong or - * on_pong_timeout callbacks. - * - * Ping locks the m_write_lock mutex - * - * @param payload Payload to be used for the ping - */ - void ping(std::string const & payload); - - /// exception free variant of ping - void ping(std::string const & payload, lib::error_code & ec); - - /// Utility method that gets called back when the ping timer expires - void handle_pong_timeout(std::string payload, lib::error_code const & ec); - - /// Send a pong - /** - * Initiates a pong with the given payload. - * - * There is no feedback from a pong once sent. - * - * Pong locks the m_write_lock mutex - * - * @param payload Payload to be used for the pong - */ - void pong(std::string const & payload); - - /// exception free variant of pong - void pong(std::string const & payload, lib::error_code & ec); - - /// Close the connection - /** - * Initiates the close handshake process. - * - * If close returns successfully the connection will be in the closing - * state and no additional messages may be sent. All messages sent prior - * to calling close will be written out before the connection is closed. - * - * If no reason is specified none will be sent. If no code is specified - * then no code will be sent. - * - * The handler's on_close callback will be called once the close handshake - * is complete. - * - * Reasons will be automatically truncated to the maximum length (123 bytes) - * if necessary. - * - * @param code The close code to send - * @param reason The close reason to send - */ - void close(close::status::value const code, std::string const & reason); - - /// exception free variant of close - void close(close::status::value const code, std::string const & reason, - lib::error_code & ec); - - //////////////////////////////////////////////// - // Pass-through access to the uri information // - //////////////////////////////////////////////// - - /// Returns the secure flag from the connection URI - /** - * This value is available after the HTTP request has been fully read and - * may be called from any thread. - * - * @return Whether or not the connection URI is flagged secure. - */ - bool get_secure() const; - - /// Returns the host component of the connection URI - /** - * This value is available after the HTTP request has been fully read and - * may be called from any thread. - * - * @return The host component of the connection URI - */ - std::string const & get_host() const; - - /// Returns the resource component of the connection URI - /** - * This value is available after the HTTP request has been fully read and - * may be called from any thread. - * - * @return The resource component of the connection URI - */ - std::string const & get_resource() const; - - /// Returns the port component of the connection URI - /** - * This value is available after the HTTP request has been fully read and - * may be called from any thread. - * - * @return The port component of the connection URI - */ - uint16_t get_port() const; - - /// Gets the connection URI - /** - * This should really only be called by internal library methods unless you - * really know what you are doing. - * - * @return A pointer to the connection's URI - */ - uri_ptr get_uri() const; - - /// Sets the connection URI - /** - * This should really only be called by internal library methods unless you - * really know what you are doing. - * - * @param uri The new URI to set - */ - void set_uri(uri_ptr uri); - - ///////////////////////////// - // Subprotocol negotiation // - ///////////////////////////// - - /// Gets the negotated subprotocol - /** - * Retrieves the subprotocol that was negotiated during the handshake. This - * method is valid in the open handler and later. - * - * @return The negotiated subprotocol - */ - std::string const & get_subprotocol() const; - - /// Gets all of the subprotocols requested by the client - /** - * Retrieves the subprotocols that were requested during the handshake. This - * method is valid in the validate handler and later. - * - * @return A vector of the requested subprotocol - */ - std::vector const & get_requested_subprotocols() const; - - /// Adds the given subprotocol string to the request list (exception free) - /** - * Adds a subprotocol to the list to send with the opening handshake. This - * may be called multiple times to request more than one. If the server - * supports one of these, it may choose one. If so, it will return it - * in it's handshake reponse and the value will be available via - * get_subprotocol(). Subprotocol requests should be added in order of - * preference. - * - * @param request The subprotocol to request - * @param ec A reference to an error code that will be filled in the case of - * errors - */ - void add_subprotocol(std::string const & request, lib::error_code & ec); - - /// Adds the given subprotocol string to the request list - /** - * Adds a subprotocol to the list to send with the opening handshake. This - * may be called multiple times to request more than one. If the server - * supports one of these, it may choose one. If so, it will return it - * in it's handshake reponse and the value will be available via - * get_subprotocol(). Subprotocol requests should be added in order of - * preference. - * - * @param request The subprotocol to request - */ - void add_subprotocol(std::string const & request); - - /// Select a subprotocol to use (exception free) - /** - * Indicates which subprotocol should be used for this connection. Valid - * only during the validate handler callback. Subprotocol selected must have - * been requested by the client. Consult get_requested_subprotocols() for a - * list of valid subprotocols. - * - * This member function is valid on server endpoints/connections only - * - * @param value The subprotocol to select - * @param ec A reference to an error code that will be filled in the case of - * errors - */ - void select_subprotocol(std::string const & value, lib::error_code & ec); - - /// Select a subprotocol to use - /** - * Indicates which subprotocol should be used for this connection. Valid - * only during the validate handler callback. Subprotocol selected must have - * been requested by the client. Consult get_requested_subprotocols() for a - * list of valid subprotocols. - * - * This member function is valid on server endpoints/connections only - * - * @param value The subprotocol to select - */ - void select_subprotocol(std::string const & value); - - ///////////////////////////////////////////////////////////// - // Pass-through access to the request and response objects // - ///////////////////////////////////////////////////////////// - - /// Retrieve a request header - /** - * Retrieve the value of a header from the handshake HTTP request. - * - * @param key Name of the header to get - * @return The value of the header - */ - std::string const & get_request_header(std::string const & key) const; - - /// Retrieve a request body - /** - * Retrieve the value of the request body. This value is typically used with - * PUT and POST requests to upload files or other data. Only HTTP - * connections will ever have bodies. WebSocket connection's will always - * have blank bodies. - * - * @return The value of the request body. - */ - std::string const & get_request_body() const; - - /// Retrieve a response header - /** - * Retrieve the value of a header from the handshake HTTP request. - * - * @param key Name of the header to get - * @return The value of the header - */ - std::string const & get_response_header(std::string const & key) const; - - /// Get response HTTP status code - /** - * Gets the response status code - * - * @since 0.7.0 - * - * @return The response status code sent - */ - http::status_code::value get_response_code() const { - return m_response.get_status_code(); - } - - /// Get response HTTP status message - /** - * Gets the response status message - * - * @since 0.7.0 - * - * @return The response status message sent - */ - std::string const & get_response_msg() const { - return m_response.get_status_msg(); - } - - /// 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. - * - * This member function is valid only from the http() and validate() handler - * callbacks. - * - * @param code Code to set - * @param msg Message to set - * @see websocketpp::http::response::set_status - */ - void set_status(http::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. - * - * This member function is valid only from the http() and validate() handler - * callbacks. - * - * @param code Code to set - * @param msg Message to set - * @see websocketpp::http::response::set_status - */ - void set_status(http::status_code::value code, std::string const & msg); - - /// Set response 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 set it - * to something else after calling set_body - * - * This member function is valid only from the http() and validate() handler - * callbacks. - * - * @param value String data to include as the body content. - * @see websocketpp::http::response::set_body - */ - void set_body(std::string const & value); - - /// Append a header - /** - * If a header with this name already exists the value will be appended to - * the existing header to form a comma separated list of values. Use - * `connection::replace_header` to overwrite existing values. - * - * This member function is valid only from the http() and validate() handler - * callbacks, or to a client connection before connect has been called. - * - * @param key Name of the header to set - * @param val Value to add - * @see replace_header - * @see websocketpp::http::parser::append_header - */ - void append_header(std::string const & key, std::string const & val); - - /// Replace a header - /** - * If a header with this name already exists the old value will be replaced - * Use `connection::append_header` to append to a list of existing values. - * - * This member function is valid only from the http() and validate() handler - * callbacks, or to a client connection before connect has been called. - * - * @param key Name of the header to set - * @param val Value to set - * @see append_header - * @see websocketpp::http::parser::replace_header - */ - void replace_header(std::string const & key, std::string const & val); - - /// Remove a header - /** - * Removes a header from the response. - * - * This member function is valid only from the http() and validate() handler - * callbacks, or to a client connection before connect has been called. - * - * @param key The name of the header to remove - * @see websocketpp::http::parser::remove_header - */ - void remove_header(std::string const & key); - - /// Get request object - /** - * Direct access to request object. This can be used to call methods of the - * request object that are not part of the standard request API that - * connection wraps. - * - * Note use of this method involves using behavior specific to the - * configured HTTP policy. Such behavior may not work with alternate HTTP - * policies. - * - * @since 0.3.0-alpha3 - * - * @return A const reference to the raw request object - */ - request_type const & get_request() const { - return m_request; - } - - /// Get response object - /** - * Direct access to the HTTP response sent or received as a part of the - * opening handshake. This can be used to call methods of the response - * object that are not part of the standard request API that connection - * wraps. - * - * Note use of this method involves using behavior specific to the - * configured HTTP policy. Such behavior may not work with alternate HTTP - * policies. - * - * @since 0.7.0 - * - * @return A const reference to the raw response object - */ - response_type const & get_response() const { - return m_response; - } - - /// Defer HTTP Response until later (Exception free) - /** - * Used in the http handler to defer the HTTP response for this connection - * until later. Handshake timers will be canceled and the connection will be - * left open until `send_http_response` or an equivalent is called. - * - * Warning: deferred connections won't time out and as a result can tie up - * resources. - * - * @since 0.6.0 - * - * @return A status code, zero on success, non-zero otherwise - */ - lib::error_code defer_http_response(); - - /// 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. - * - * @since 0.6.0 - * - * @param ec A status code, zero on success, non-zero otherwise - */ - void send_http_response(lib::error_code & ec); - - /// Send deferred HTTP Response - void send_http_response(); - - // TODO HTTPNBIO: write_headers - // function that processes headers + status so far and writes it to the wire - // beginning the HTTP response body state. This method will ignore anything - // in the response body. - - // TODO HTTPNBIO: write_body_message - // queues the specified message_buffer for async writing - - // TODO HTTPNBIO: finish connection - // - - // TODO HTTPNBIO: write_response - // Writes the whole response, headers + body and closes the connection - - - - ///////////////////////////////////////////////////////////// - // Pass-through access to the other connection information // - ///////////////////////////////////////////////////////////// - - /// Get Connection Handle - /** - * The connection handle is a token that can be shared outside the - * WebSocket++ core for the purposes of identifying a connection and - * sending it messages. - * - * @return A handle to the connection - */ - connection_hdl get_handle() const { - return m_connection_hdl; - } - - /// Get whether or not this connection is part of a server or client - /** - * @return whether or not the connection is attached to a server endpoint - */ - bool is_server() const { - return m_is_server; - } - - /// Return the same origin policy origin value from the opening request. - /** - * This value is available after the HTTP request has been fully read and - * may be called from any thread. - * - * @return The connection's origin value from the opening handshake. - */ - std::string const & get_origin() const; - - /// Return the connection state. - /** - * Values can be connecting, open, closing, and closed - * - * @return The connection's current state. - */ - session::state::value get_state() const; - - - /// Get the WebSocket close code sent by this endpoint. - /** - * @return The WebSocket close code sent by this endpoint. - */ - close::status::value get_local_close_code() const { - return m_local_close_code; - } - - /// Get the WebSocket close reason sent by this endpoint. - /** - * @return The WebSocket close reason sent by this endpoint. - */ - std::string const & get_local_close_reason() const { - return m_local_close_reason; - } - - /// Get the WebSocket close code sent by the remote endpoint. - /** - * @return The WebSocket close code sent by the remote endpoint. - */ - close::status::value get_remote_close_code() const { - return m_remote_close_code; - } - - /// Get the WebSocket close reason sent by the remote endpoint. - /** - * @return The WebSocket close reason sent by the remote endpoint. - */ - std::string const & get_remote_close_reason() const { - return m_remote_close_reason; - } - - /// Get the internal error code for a closed/failed connection - /** - * Retrieves a machine readable detailed error code indicating the reason - * that the connection was closed or failed. Valid only after the close or - * fail handler is called. - * - * @return Error code indicating the reason the connection was closed or - * failed - */ - lib::error_code get_ec() const { - return m_ec; - } - - /// Get a message buffer - /** - * Warning: The API related to directly sending message buffers may change - * before the 1.0 release. If you plan to use it, please keep an eye on any - * breaking changes notifications in future release notes. Also if you have - * any feedback about usage and capabilities now is a great time to provide - * it. - * - * Message buffers are used to store message payloads and other message - * metadata. - * - * The size parameter is a hint only. Your final payload does not need to - * match it. There may be some performance benefits if the initial size - * guess is equal to or slightly higher than the final payload size. - * - * @param op The opcode for the new message - * @param size A hint to optimize the initial allocation of payload space. - * @return A new message buffer - */ - message_ptr get_message(websocketpp::frame::opcode::value op, size_t size) - const - { - return m_msg_manager->get_message(op, size); - } - - //////////////////////////////////////////////////////////////////////// - // The remaining public member functions are for internal/policy use // - // only. Do not call from application code unless you understand what // - // you are doing. // - //////////////////////////////////////////////////////////////////////// - - - - void read_handshake(size_t num_bytes); - - void handle_read_handshake(lib::error_code const & ec, - size_t bytes_transferred); - void handle_read_http_response(lib::error_code const & ec, - size_t bytes_transferred); - - - void handle_write_http_response(lib::error_code const & ec); - void handle_send_http_request(lib::error_code const & ec); - - void handle_open_handshake_timeout(lib::error_code const & ec); - void handle_close_handshake_timeout(lib::error_code const & ec); - - void handle_read_frame(lib::error_code const & ec, size_t bytes_transferred); - void read_frame(); - - /// Get array of WebSocket protocol versions that this connection supports. - std::vector const & get_supported_versions() const; - - /// Sets the handler for a terminating connection. Should only be used - /// internally by the endpoint class. - void set_termination_handler(termination_handler new_handler); - - void terminate(lib::error_code const & ec); - void handle_terminate(terminate_status tstat, lib::error_code const & ec); - - /// Checks if there are frames in the send queue and if there are sends one - /** - * \todo unit tests - * - * This method locks the m_write_lock mutex - */ - void write_frame(); - - /// Process the results of a frame write operation and start the next write - /** - * \todo unit tests - * - * This method locks the m_write_lock mutex - * - * @param terminate Whether or not to terminate the connection upon - * completion of this write. - * - * @param ec A status code from the transport layer, zero on success, - * non-zero otherwise. - */ - void handle_write_frame(lib::error_code const & ec); -// protected: - // This set of methods would really like to be protected, but doing so - // requires that the endpoint be able to friend the connection. This is - // allowed with C++11, but not prior versions - - /// Start the connection state machine - void start(); - - /// Set Connection Handle - /** - * The connection handle is a token that can be shared outside the - * WebSocket++ core for the purposes of identifying a connection and - * sending it messages. - * - * @param hdl A connection_hdl that the connection will use to refer - * to itself. - */ - void set_handle(connection_hdl hdl) { - m_connection_hdl = hdl; - transport_con_type::set_handle(hdl); - } -protected: - void handle_transport_init(lib::error_code const & ec); - - /// Set m_processor based on information in m_request. Set m_response - /// status and return an error code indicating status. - lib::error_code initialize_processor(); - - /// Perform WebSocket handshake validation of m_request using m_processor. - /// set m_response and return an error code indicating status. - lib::error_code process_handshake_request(); -private: - - - /// Completes m_response, serializes it, and sends it out on the wire. - void write_http_response(lib::error_code const & ec); - - /// Sends an opening WebSocket connect request - void send_http_request(); - - /// Alternate path for write_http_response in error conditions - void write_http_response_error(lib::error_code const & ec); - - /// Process control message - /** - * - */ - void process_control_frame(message_ptr msg); - - /// Send close acknowledgement - /** - * If no arguments are present no close code/reason will be specified. - * - * Note: the close code/reason values provided here may be overrided by - * other settings (such as silent close). - * - * @param code The close code to send - * @param reason The close reason to send - * @return A status code, zero on success, non-zero otherwise - */ - lib::error_code send_close_ack(close::status::value code = - close::status::blank, std::string const & reason = std::string()); - - /// Send close frame - /** - * If no arguments are present no close code/reason will be specified. - * - * Note: the close code/reason values provided here may be overrided by - * other settings (such as silent close). - * - * The ack flag determines what to do in the case of a blank status and - * whether or not to terminate the TCP connection after sending it. - * - * @param code The close code to send - * @param reason The close reason to send - * @param ack Whether or not this is an acknowledgement close frame - * @return A status code, zero on success, non-zero otherwise - */ - lib::error_code send_close_frame(close::status::value code = - close::status::blank, std::string const & reason = std::string(), bool ack = false, - bool terminal = false); - - /// Get a pointer to a new WebSocket protocol processor for a given version - /** - * @param version Version number of the WebSocket protocol to get a - * processor for. Negative values indicate invalid/unknown versions and will - * always return a null ptr - * - * @return A shared_ptr to a new instance of the appropriate processor or a - * null ptr if there is no installed processor that matches the version - * number. - */ - processor_ptr get_processor(int version) const; - - /// Add a message to the write queue - /** - * Adds a message to the write queue and updates any associated shared state - * - * Must be called while holding m_write_lock - * - * @todo unit tests - * - * @param msg The message to push - */ - void write_push(message_ptr msg); - - /// Pop a message from the write queue - /** - * Removes and returns a message from the write queue and updates any - * associated shared state. - * - * Must be called while holding m_write_lock - * - * @todo unit tests - * - * @return the message_ptr at the front of the queue - */ - message_ptr write_pop(); - - /// Prints information about the incoming connection to the access log - /** - * Prints information about the incoming connection to the access log. - * Includes: connection type, websocket version, remote endpoint, user agent - * path, status code. - */ - void log_open_result(); - - /// Prints information about a connection being closed to the access log - /** - * Includes: local and remote close codes and reasons - */ - void log_close_result(); - - /// Prints information about a connection being failed to the access log - /** - * Includes: error code and message for why it was failed - */ - void log_fail_result(); - - /// Prints information about HTTP connections - /** - * Includes: TODO - */ - void log_http_result(); - - /// Prints information about an arbitrary error code on the specified channel - template - void log_err(log::level l, char const * msg, error_type const & ec) { - std::stringstream s; - s << msg << " error: " << ec << " (" << ec.message() << ")"; - m_elog->write(l, s.str()); - } - - // internal handler functions - read_handler m_handle_read_frame; - write_frame_handler m_write_frame_handler; - - // static settings - std::string const m_user_agent; - - /// Pointer to the connection handle - connection_hdl m_connection_hdl; - - /// Handler objects - 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; - - /// constant values - long m_open_handshake_timeout_dur; - long m_close_handshake_timeout_dur; - long m_pong_timeout_dur; - size_t m_max_message_size; - - /// External connection state - /** - * Lock: m_connection_state_lock - */ - session::state::value m_state; - - /// Internal connection state - /** - * Lock: m_connection_state_lock - */ - istate_type m_internal_state; - - mutable mutex_type m_connection_state_lock; - - /// The lock used to protect the message queue - /** - * Serializes access to the write queue as well as shared state within the - * processor. - */ - mutex_type m_write_lock; - - // connection resources - char m_buf[config::connection_read_buffer_size]; - size_t m_buf_cursor; - termination_handler m_termination_handler; - con_msg_manager_ptr m_msg_manager; - timer_ptr m_handshake_timer; - timer_ptr m_ping_timer; - - /// @todo this is not memory efficient. this value is not used after the - /// handshake. - std::string m_handshake_buffer; - - /// Pointer to the processor object for this connection - /** - * The processor provides functionality that is specific to the WebSocket - * protocol version that the client has negotiated. It also contains all of - * the state necessary to encode and decode the incoming and outgoing - * WebSocket byte streams - * - * Use of the prepare_data_frame method requires lock: m_write_lock - */ - processor_ptr m_processor; - - /// Queue of unsent outgoing messages - /** - * Lock: m_write_lock - */ - std::queue m_send_queue; - - /// Size in bytes of the outstanding payloads in the write queue - /** - * Lock: m_write_lock - */ - size_t m_send_buffer_size; - - /// buffer holding the various parts of the current message being writen - /** - * Lock m_write_lock - */ - std::vector m_send_buffer; - - /// a list of pointers to hold on to the messages being written to keep them - /// from going out of scope before the write is complete. - std::vector m_current_msgs; - - /// True if there is currently an outstanding transport write - /** - * Lock m_write_lock - */ - bool m_write_flag; - - /// True if this connection is presently reading new data - bool m_read_flag; - - // connection data - request_type m_request; - response_type m_response; - uri_ptr m_uri; - std::string m_subprotocol; - - // connection data that might not be necessary to keep around for the life - // of the whole connection. - std::vector m_requested_subprotocols; - - bool const m_is_server; - const lib::shared_ptr m_alog; - const lib::shared_ptr m_elog; - - rng_type & m_rng; - - // Close state - /// Close code that was sent on the wire by this endpoint - close::status::value m_local_close_code; - - /// Close reason that was sent on the wire by this endpoint - std::string m_local_close_reason; - - /// Close code that was received on the wire from the remote endpoint - close::status::value m_remote_close_code; - - /// Close reason that was received on the wire from the remote endpoint - std::string m_remote_close_reason; - - /// Detailed internal error code - lib::error_code m_ec; - - /// A flag that gets set once it is determined that the connection is an - /// HTTP connection and not a WebSocket one. - bool m_is_http; - - /// A flag that gets set when the completion of an http connection is - /// deferred until later. - session::http_state::value m_http_state; - - bool m_was_clean; -}; - -} // namespace websocketpp - -#include - -#endif // WEBSOCKETPP_CONNECTION_HPP +/* + * 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_HPP +#define WEBSOCKETPP_CONNECTION_HPP + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace websocketpp { + +/// The type and function signature of an open handler +/** + * The open handler is called once for every successful WebSocket connection + * attempt. Either the fail handler or the open handler will be called for each + * WebSocket connection attempt. HTTP Connections that did not attempt to + * upgrade the connection to the WebSocket protocol will trigger the http + * handler instead of fail/open. + */ +typedef lib::function open_handler; + +/// The type and function signature of a close handler +/** + * The close handler is called once for every successfully established + * connection after it is no longer capable of sending or receiving new messages + * + * The close handler will be called exactly once for every connection for which + * the open handler was called. + */ +typedef lib::function close_handler; + +/// The type and function signature of a fail handler +/** + * The fail handler is called once for every unsuccessful WebSocket connection + * attempt. Either the fail handler or the open handler will be called for each + * WebSocket connection attempt. HTTP Connections that did not attempt to + * upgrade the connection to the WebSocket protocol will trigger the http + * handler instead of fail/open. + */ +typedef lib::function fail_handler; + +/// The type and function signature of an interrupt handler +/** + * The interrupt handler is called when a connection receives an interrupt + * request from the application. Interrupts allow the application to trigger a + * handler to be run in the absense of a WebSocket level handler trigger (like + * a new message). + * + * This is typically used by another application thread to schedule some tasks + * that can only be run from within the handler chain for thread safety reasons. + */ +typedef lib::function interrupt_handler; + +/// The type and function signature of a ping handler +/** + * The ping handler is called when the connection receives a WebSocket ping + * control frame. The string argument contains the ping payload. The payload is + * a binary string up to 126 bytes in length. The ping handler returns a bool, + * true if a pong response should be sent, false if the pong response should be + * suppressed. + */ +typedef lib::function ping_handler; + +/// The type and function signature of a pong handler +/** + * The pong handler is called when the connection receives a WebSocket pong + * control frame. The string argument contains the pong payload. The payload is + * a binary string up to 126 bytes in length. + */ +typedef lib::function pong_handler; + +/// The type and function signature of a pong timeout handler +/** + * The pong timeout handler is called when a ping goes unanswered by a pong for + * longer than the locally specified timeout period. + */ +typedef lib::function pong_timeout_handler; + +/// The type and function signature of a validate handler +/** + * The validate handler is called after a WebSocket handshake has been received + * and processed but before it has been accepted. This gives the application a + * chance to implement connection details specific policies for accepting + * connections and the ability to negotiate extensions and subprotocols. + * + * The validate handler return value indicates whether or not the connection + * should be accepted. Additional methods may be called during the function to + * set response headers, set HTTP return/error codes, etc. + */ +typedef lib::function validate_handler; + +/// The type and function signature of a http handler +/** + * The http handler is called when an HTTP connection is made that does not + * attempt to upgrade the connection to the WebSocket protocol. This allows + * WebSocket++ servers to respond to these requests with regular HTTP responses. + * + * This can be used to deliver error pages & dashboards and to deliver static + * files such as the base HTML & JavaScript for an otherwise single page + * WebSocket application. + * + * Note: WebSocket++ is designed to be a high performance WebSocket server. It + * is not tuned to provide a full featured, high performance, HTTP web server + * solution. The HTTP handler is appropriate only for low volume HTTP traffic. + * If you expect to serve high volumes of HTTP traffic a dedicated HTTP web + * server is strongly recommended. + * + * The default HTTP handler will return a 426 Upgrade Required error. Custom + * handlers may override the response status code to deliver any type of + * response. + */ +typedef lib::function http_handler; + +// +typedef lib::function read_handler; +typedef lib::function write_frame_handler; + +// constants related to the default WebSocket protocol versions available +#ifdef _WEBSOCKETPP_INITIALIZER_LISTS_ // simplified C++11 version + /// Container that stores the list of protocol versions supported + /** + * @todo Move this to configs to allow compile/runtime disabling or enabling + * of protocol versions + */ + static std::vector const versions_supported = {0,7,8,13}; +#else + /// Helper array to get around lack of initializer lists pre C++11 + static int const helper[] = {0,7,8,13}; + /// Container that stores the list of protocol versions supported + /** + * @todo Move this to configs to allow compile/runtime disabling or enabling + * of protocol versions + */ + static std::vector const versions_supported(helper,helper+4); +#endif + +namespace session { +namespace state { + // externally visible session state (states based on the RFC) + enum value { + connecting = 0, + open = 1, + closing = 2, + closed = 3 + }; +} // namespace state + + +namespace fail { +namespace status { + enum value { + GOOD = 0, // no failure yet! + SYSTEM = 1, // system call returned error, check that code + WEBSOCKET = 2, // websocket close codes contain error + UNKNOWN = 3, // No failure information is available + TIMEOUT_TLS = 4, // TLS handshake timed out + TIMEOUT_WS = 5 // WS handshake timed out + }; +} // namespace status +} // namespace fail + +namespace internal_state { + // More granular internal states. These are used for multi-threaded + // connection synchronization and preventing values that are not yet or no + // longer available from being used. + + enum value { + USER_INIT = 0, + TRANSPORT_INIT = 1, + READ_HTTP_REQUEST = 2, + WRITE_HTTP_REQUEST = 3, + READ_HTTP_RESPONSE = 4, + WRITE_HTTP_RESPONSE = 5, + PROCESS_HTTP_REQUEST = 6, + PROCESS_CONNECTION = 7 + }; +} // namespace internal_state + + +namespace http_state { + // states to keep track of the progress of http connections + + enum value { + init = 0, + deferred = 1, + headers_written = 2, + body_written = 3, + closed = 4 + }; +} // namespace http_state + +} // namespace session + +/// Represents an individual WebSocket connection +template +class connection + : public config::transport_type::transport_con_type + , public config::connection_base +{ +public: + /// Type of this connection + typedef connection type; + /// Type of a shared pointer to this connection + typedef lib::shared_ptr ptr; + /// Type of a weak pointer to this connection + typedef lib::weak_ptr weak_ptr; + + /// Type of the concurrency component of this connection + typedef typename config::concurrency_type concurrency_type; + /// Type of the access logging policy + typedef typename config::alog_type alog_type; + /// Type of the error logging policy + typedef typename config::elog_type elog_type; + + /// Type of the transport component of this connection + typedef typename config::transport_type::transport_con_type + transport_con_type; + /// Type of a shared pointer to the transport component of this connection + typedef typename transport_con_type::ptr transport_con_ptr; + + typedef lib::function termination_handler; + + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + 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 con_msg_manager_type; + typedef typename con_msg_manager_type::ptr con_msg_manager_ptr; + + /// Type of RNG + typedef typename config::rng_type rng_type; + + typedef processor::processor processor_type; + typedef lib::shared_ptr processor_ptr; + + // Message handler (needs to know message type) + typedef lib::function message_handler; + + /// Type of a pointer to a transport timer handle + typedef typename transport_con_type::timer_ptr timer_ptr; + + // Misc Convenience Types + typedef session::internal_state::value istate_type; + +private: + enum terminate_status { + failed = 1, + closed, + unknown + }; +public: + + explicit connection(bool p_is_server, std::string const & ua, const lib::shared_ptr& alog, + const lib::shared_ptr& elog, rng_type & rng) + : transport_con_type(p_is_server, alog, elog) + , m_handle_read_frame(lib::bind( + &type::handle_read_frame, + this, + lib::placeholders::_1, + lib::placeholders::_2 + )) + , m_write_frame_handler(lib::bind( + &type::handle_write_frame, + this, + lib::placeholders::_1 + )) + , m_user_agent(ua) + , 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_state(session::state::connecting) + , m_internal_state(session::internal_state::USER_INIT) + , m_msg_manager(new con_msg_manager_type()) + , m_send_buffer_size(0) + , m_write_flag(false) + , m_read_flag(true) + , m_is_server(p_is_server) + , m_alog(alog) + , m_elog(elog) + , m_rng(rng) + , m_local_close_code(close::status::abnormal_close) + , m_remote_close_code(close::status::abnormal_close) + , m_is_http(false) + , m_http_state(session::http_state::init) + , m_was_clean(false) + { + m_alog->write(log::alevel::devel,"connection constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return lib::static_pointer_cast(transport_con_type::get_shared()); + } + + /////////////////////////// + // Set Handler Callbacks // + /////////////////////////// + + /// Set open handler + /** + * The open handler is called after the WebSocket handshake is complete and + * the connection is considered OPEN. + * + * @param h The new open_handler + */ + void set_open_handler(open_handler h) { + m_open_handler = h; + } + + /// Set close handler + /** + * The close handler is called immediately after the connection is closed. + * + * @param h The new close_handler + */ + void set_close_handler(close_handler h) { + m_close_handler = h; + } + + /// Set fail handler + /** + * The fail handler is called whenever the connection fails while the + * handshake is bring processed. + * + * @param h The new fail_handler + */ + void set_fail_handler(fail_handler h) { + m_fail_handler = h; + } + + /// Set ping handler + /** + * The ping handler is called whenever the connection receives a ping + * control frame. The ping payload is included. + * + * The ping handler's return time controls whether or not a pong is + * sent in response to this ping. Returning false will suppress the + * return pong. If no ping handler is set a pong will be sent. + * + * @param h The new ping_handler + */ + void set_ping_handler(ping_handler h) { + m_ping_handler = h; + } + + /// Set pong handler + /** + * The pong handler is called whenever the connection receives a pong + * control frame. The pong payload is included. + * + * @param h The new pong_handler + */ + void set_pong_handler(pong_handler h) { + m_pong_handler = h; + } + + /// Set pong timeout handler + /** + * If the transport component being used supports timers, the pong timeout + * handler is called whenever a pong control frame is not received with the + * configured timeout period after the application sends a ping. + * + * The config setting `timeout_pong` controls the length of the timeout + * period. It is specified in milliseconds. + * + * This can be used to probe the health of the remote endpoint's WebSocket + * implementation. This does not guarantee that the remote application + * itself is still healthy but can be a useful diagnostic. + * + * Note: receipt of this callback doesn't mean the pong will never come. + * This functionality will not suppress delivery of the pong in question + * should it arrive after the timeout. + * + * @param h The new pong_timeout_handler + */ + void set_pong_timeout_handler(pong_timeout_handler h) { + m_pong_timeout_handler = h; + } + + /// Set interrupt handler + /** + * The interrupt handler is called whenever the connection is manually + * interrupted by the application. + * + * @param h The new interrupt_handler + */ + void set_interrupt_handler(interrupt_handler h) { + m_interrupt_handler = h; + } + + /// Set http handler + /** + * The http handler is called after an HTTP request other than a WebSocket + * upgrade request is received. It allows a WebSocket++ server to respond + * to regular HTTP requests on the same port as it processes WebSocket + * connections. This can be useful for hosting error messages, flash + * policy files, status pages, and other simple HTTP responses. It is not + * intended to be used as a primary web server. + * + * @param h The new http_handler + */ + void set_http_handler(http_handler h) { + m_http_handler = h; + } + + /// Set validate handler + /** + * The validate handler is called after a WebSocket handshake has been + * parsed but before a response is returned. It provides the application + * a chance to examine the request and determine whether or not it wants + * to accept the connection. + * + * Returning false from the validate handler will reject the connection. + * If no validate handler is present, all connections will be allowed. + * + * @param h The new validate_handler + */ + void set_validate_handler(validate_handler h) { + m_validate_handler = h; + } + + /// Set message handler + /** + * The message handler is called after a new message has been received. + * + * @param h The new message_handler + */ + void set_message_handler(message_handler h) { + 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) { + 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) { + 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) { + m_pong_timeout_dur = dur; + } + + /// Get maximum message size + /** + * Get maximum message size. Maximum message size determines the point at + * which the connection will fail with the message_too_big protocol error. + * + * The default is set by the endpoint that creates the connection. + * + * @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 connection will fail with the message_too_big protocol error. + * This value may be changed during the connection. + * + * The default is set by the endpoint that creates the connection. + * + * @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; + if (m_processor) { + m_processor->set_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 endpoint that creates the connection. + * + * @since 0.5.0 + * + * @return The maximum HTTP message body size + */ + size_t get_max_http_body_size() const { + return m_request.get_max_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 endpoint that creates the connection. + * + * @since 0.5.0 + * + * @param new_value The value to set as the maximum message size. + */ + void set_max_http_body_size(size_t new_value) { + m_request.set_max_body_size(new_value); + } + + ////////////////////////////////// + // Uncategorized public methods // + ////////////////////////////////// + + /// Get the size of the outgoing write buffer (in payload bytes) + /** + * Retrieves the number of bytes in the outgoing write buffer that have not + * already been dispatched to the transport layer. This represents the bytes + * that are presently cancelable without uncleanly ending the websocket + * connection + * + * This method invokes the m_write_lock mutex + * + * @return The current number of bytes in the outgoing send buffer. + */ + size_t get_buffered_amount() const; + + /// Get the size of the outgoing write buffer (in payload bytes) + /** + * @deprecated use `get_buffered_amount` instead + */ + size_t buffered_amount() const { + return get_buffered_amount(); + } + + //////////////////// + // Action Methods // + //////////////////// + + /// Create a message and then add it to the outgoing send queue + /** + * Convenience method to send a message given a payload string and + * optionally an opcode. Default opcode is utf8 text. + * + * This method locks the m_write_lock mutex + * + * @param payload The payload string to generated the message with + * + * @param op The opcode to generated the message with. Default is + * frame::opcode::text + */ + lib::error_code send(std::string const & payload, frame::opcode::value op = + frame::opcode::text); + + /// Send a message (raw array overload) + /** + * Convenience method to send a message given a raw array and optionally an + * opcode. Default opcode is binary. + * + * This method locks the m_write_lock mutex + * + * @param payload A pointer to the array containing the bytes to send. + * + * @param len Length of the array. + * + * @param op The opcode to generated the message with. Default is + * frame::opcode::binary + */ + lib::error_code send(void const * payload, size_t len, frame::opcode::value + op = frame::opcode::binary); + + /// Add a message to the outgoing send queue + /** + * If presented with a prepared message it is added without validation or + * framing. If presented with an unprepared message it is validated, framed, + * and then added + * + * Errors are returned via an exception + * \todo make exception system_error rather than error_code + * + * This method invokes the m_write_lock mutex + * + * @param msg A message_ptr to the message to send. + */ + lib::error_code send(message_ptr msg); + + /// Asyncronously invoke handler::on_inturrupt + /** + * Signals to the connection to asyncronously invoke the on_inturrupt + * callback for this connection's handler once it is safe to do so. + * + * When the on_inturrupt handler callback is called it will be from + * within the transport event loop with all the thread safety features + * guaranteed by the transport to regular handlers + * + * Multiple inturrupt signals can be active at once on the same connection + * + * @return An error code + */ + lib::error_code interrupt(); + + /// Transport inturrupt callback + void handle_interrupt(); + + /// Pause reading of new data + /** + * 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. + */ + lib::error_code pause_reading(); + + /// Pause reading callback + void handle_pause_reading(); + + /// Resume reading of new data + /** + * 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. + */ + lib::error_code resume_reading(); + + /// Resume reading callback + void handle_resume_reading(); + + /// Send a ping + /** + * Initiates a ping with the given payload/ + * + * There is no feedback directly from ping except in cases of immediately + * detectable errors. Feedback will be provided via on_pong or + * on_pong_timeout callbacks. + * + * Ping locks the m_write_lock mutex + * + * @param payload Payload to be used for the ping + */ + void ping(std::string const & payload); + + /// exception free variant of ping + void ping(std::string const & payload, lib::error_code & ec); + + /// Utility method that gets called back when the ping timer expires + void handle_pong_timeout(std::string payload, lib::error_code const & ec); + + /// Send a pong + /** + * Initiates a pong with the given payload. + * + * There is no feedback from a pong once sent. + * + * Pong locks the m_write_lock mutex + * + * @param payload Payload to be used for the pong + */ + void pong(std::string const & payload); + + /// exception free variant of pong + void pong(std::string const & payload, lib::error_code & ec); + + /// Close the connection + /** + * Initiates the close handshake process. + * + * If close returns successfully the connection will be in the closing + * state and no additional messages may be sent. All messages sent prior + * to calling close will be written out before the connection is closed. + * + * If no reason is specified none will be sent. If no code is specified + * then no code will be sent. + * + * The handler's on_close callback will be called once the close handshake + * is complete. + * + * Reasons will be automatically truncated to the maximum length (123 bytes) + * if necessary. + * + * @param code The close code to send + * @param reason The close reason to send + */ + void close(close::status::value const code, std::string const & reason); + + /// exception free variant of close + void close(close::status::value const code, std::string const & reason, + lib::error_code & ec); + + //////////////////////////////////////////////// + // Pass-through access to the uri information // + //////////////////////////////////////////////// + + /// Returns the secure flag from the connection URI + /** + * This value is available after the HTTP request has been fully read and + * may be called from any thread. + * + * @return Whether or not the connection URI is flagged secure. + */ + bool get_secure() const; + + /// Returns the host component of the connection URI + /** + * This value is available after the HTTP request has been fully read and + * may be called from any thread. + * + * @return The host component of the connection URI + */ + std::string const & get_host() const; + + /// Returns the resource component of the connection URI + /** + * This value is available after the HTTP request has been fully read and + * may be called from any thread. + * + * @return The resource component of the connection URI + */ + std::string const & get_resource() const; + + /// Returns the port component of the connection URI + /** + * This value is available after the HTTP request has been fully read and + * may be called from any thread. + * + * @return The port component of the connection URI + */ + uint16_t get_port() const; + + /// Gets the connection URI + /** + * This should really only be called by internal library methods unless you + * really know what you are doing. + * + * @return A pointer to the connection's URI + */ + uri_ptr get_uri() const; + + /// Sets the connection URI + /** + * This should really only be called by internal library methods unless you + * really know what you are doing. + * + * @param uri The new URI to set + */ + void set_uri(uri_ptr uri); + + ///////////////////////////// + // Subprotocol negotiation // + ///////////////////////////// + + /// Gets the negotated subprotocol + /** + * Retrieves the subprotocol that was negotiated during the handshake. This + * method is valid in the open handler and later. + * + * @return The negotiated subprotocol + */ + std::string const & get_subprotocol() const; + + /// Gets all of the subprotocols requested by the client + /** + * Retrieves the subprotocols that were requested during the handshake. This + * method is valid in the validate handler and later. + * + * @return A vector of the requested subprotocol + */ + std::vector const & get_requested_subprotocols() const; + + /// Adds the given subprotocol string to the request list (exception free) + /** + * Adds a subprotocol to the list to send with the opening handshake. This + * may be called multiple times to request more than one. If the server + * supports one of these, it may choose one. If so, it will return it + * in it's handshake reponse and the value will be available via + * get_subprotocol(). Subprotocol requests should be added in order of + * preference. + * + * @param request The subprotocol to request + * @param ec A reference to an error code that will be filled in the case of + * errors + */ + void add_subprotocol(std::string const & request, lib::error_code & ec); + + /// Adds the given subprotocol string to the request list + /** + * Adds a subprotocol to the list to send with the opening handshake. This + * may be called multiple times to request more than one. If the server + * supports one of these, it may choose one. If so, it will return it + * in it's handshake reponse and the value will be available via + * get_subprotocol(). Subprotocol requests should be added in order of + * preference. + * + * @param request The subprotocol to request + */ + void add_subprotocol(std::string const & request); + + /// Select a subprotocol to use (exception free) + /** + * Indicates which subprotocol should be used for this connection. Valid + * only during the validate handler callback. Subprotocol selected must have + * been requested by the client. Consult get_requested_subprotocols() for a + * list of valid subprotocols. + * + * This member function is valid on server endpoints/connections only + * + * @param value The subprotocol to select + * @param ec A reference to an error code that will be filled in the case of + * errors + */ + void select_subprotocol(std::string const & value, lib::error_code & ec); + + /// Select a subprotocol to use + /** + * Indicates which subprotocol should be used for this connection. Valid + * only during the validate handler callback. Subprotocol selected must have + * been requested by the client. Consult get_requested_subprotocols() for a + * list of valid subprotocols. + * + * This member function is valid on server endpoints/connections only + * + * @param value The subprotocol to select + */ + void select_subprotocol(std::string const & value); + + ///////////////////////////////////////////////////////////// + // Pass-through access to the request and response objects // + ///////////////////////////////////////////////////////////// + + /// Retrieve a request header + /** + * Retrieve the value of a header from the handshake HTTP request. + * + * @param key Name of the header to get + * @return The value of the header + */ + std::string const & get_request_header(std::string const & key) const; + + /// Retrieve a request body + /** + * Retrieve the value of the request body. This value is typically used with + * PUT and POST requests to upload files or other data. Only HTTP + * connections will ever have bodies. WebSocket connection's will always + * have blank bodies. + * + * @return The value of the request body. + */ + std::string const & get_request_body() const; + + /// Retrieve a response header + /** + * Retrieve the value of a header from the handshake HTTP request. + * + * @param key Name of the header to get + * @return The value of the header + */ + std::string const & get_response_header(std::string const & key) const; + + /// Get response HTTP status code + /** + * Gets the response status code + * + * @since 0.7.0 + * + * @return The response status code sent + */ + http::status_code::value get_response_code() const { + return m_response.get_status_code(); + } + + /// Get response HTTP status message + /** + * Gets the response status message + * + * @since 0.7.0 + * + * @return The response status message sent + */ + std::string const & get_response_msg() const { + return m_response.get_status_msg(); + } + + /// 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. + * + * This member function is valid only from the http() and validate() handler + * callbacks. + * + * @param code Code to set + * @param msg Message to set + * @see websocketpp::http::response::set_status + */ + void set_status(http::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. + * + * This member function is valid only from the http() and validate() handler + * callbacks. + * + * @param code Code to set + * @param msg Message to set + * @see websocketpp::http::response::set_status + */ + void set_status(http::status_code::value code, std::string const & msg); + + /// Set response 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 set it + * to something else after calling set_body + * + * This member function is valid only from the http() and validate() handler + * callbacks. + * + * @param value String data to include as the body content. + * @see websocketpp::http::response::set_body + */ + void set_body(std::string const & value); + + /// Append a header + /** + * If a header with this name already exists the value will be appended to + * the existing header to form a comma separated list of values. Use + * `connection::replace_header` to overwrite existing values. + * + * This member function is valid only from the http() and validate() handler + * callbacks, or to a client connection before connect has been called. + * + * @param key Name of the header to set + * @param val Value to add + * @see replace_header + * @see websocketpp::http::parser::append_header + */ + void append_header(std::string const & key, std::string const & val); + + /// Replace a header + /** + * If a header with this name already exists the old value will be replaced + * Use `connection::append_header` to append to a list of existing values. + * + * This member function is valid only from the http() and validate() handler + * callbacks, or to a client connection before connect has been called. + * + * @param key Name of the header to set + * @param val Value to set + * @see append_header + * @see websocketpp::http::parser::replace_header + */ + void replace_header(std::string const & key, std::string const & val); + + /// Remove a header + /** + * Removes a header from the response. + * + * This member function is valid only from the http() and validate() handler + * callbacks, or to a client connection before connect has been called. + * + * @param key The name of the header to remove + * @see websocketpp::http::parser::remove_header + */ + void remove_header(std::string const & key); + + /// Get request object + /** + * Direct access to request object. This can be used to call methods of the + * request object that are not part of the standard request API that + * connection wraps. + * + * Note use of this method involves using behavior specific to the + * configured HTTP policy. Such behavior may not work with alternate HTTP + * policies. + * + * @since 0.3.0-alpha3 + * + * @return A const reference to the raw request object + */ + request_type const & get_request() const { + return m_request; + } + + /// Get response object + /** + * Direct access to the HTTP response sent or received as a part of the + * opening handshake. This can be used to call methods of the response + * object that are not part of the standard request API that connection + * wraps. + * + * Note use of this method involves using behavior specific to the + * configured HTTP policy. Such behavior may not work with alternate HTTP + * policies. + * + * @since 0.7.0 + * + * @return A const reference to the raw response object + */ + response_type const & get_response() const { + return m_response; + } + + /// Defer HTTP Response until later (Exception free) + /** + * Used in the http handler to defer the HTTP response for this connection + * until later. Handshake timers will be canceled and the connection will be + * left open until `send_http_response` or an equivalent is called. + * + * Warning: deferred connections won't time out and as a result can tie up + * resources. + * + * @since 0.6.0 + * + * @return A status code, zero on success, non-zero otherwise + */ + lib::error_code defer_http_response(); + + /// 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. + * + * @since 0.6.0 + * + * @param ec A status code, zero on success, non-zero otherwise + */ + void send_http_response(lib::error_code & ec); + + /// Send deferred HTTP Response + void send_http_response(); + + // TODO HTTPNBIO: write_headers + // function that processes headers + status so far and writes it to the wire + // beginning the HTTP response body state. This method will ignore anything + // in the response body. + + // TODO HTTPNBIO: write_body_message + // queues the specified message_buffer for async writing + + // TODO HTTPNBIO: finish connection + // + + // TODO HTTPNBIO: write_response + // Writes the whole response, headers + body and closes the connection + + + + ///////////////////////////////////////////////////////////// + // Pass-through access to the other connection information // + ///////////////////////////////////////////////////////////// + + /// Get Connection Handle + /** + * The connection handle is a token that can be shared outside the + * WebSocket++ core for the purposes of identifying a connection and + * sending it messages. + * + * @return A handle to the connection + */ + connection_hdl get_handle() const { + return m_connection_hdl; + } + + /// Get whether or not this connection is part of a server or client + /** + * @return whether or not the connection is attached to a server endpoint + */ + bool is_server() const { + return m_is_server; + } + + /// Return the same origin policy origin value from the opening request. + /** + * This value is available after the HTTP request has been fully read and + * may be called from any thread. + * + * @return The connection's origin value from the opening handshake. + */ + std::string const & get_origin() const; + + /// Return the connection state. + /** + * Values can be connecting, open, closing, and closed + * + * @return The connection's current state. + */ + session::state::value get_state() const; + + + /// Get the WebSocket close code sent by this endpoint. + /** + * @return The WebSocket close code sent by this endpoint. + */ + close::status::value get_local_close_code() const { + return m_local_close_code; + } + + /// Get the WebSocket close reason sent by this endpoint. + /** + * @return The WebSocket close reason sent by this endpoint. + */ + std::string const & get_local_close_reason() const { + return m_local_close_reason; + } + + /// Get the WebSocket close code sent by the remote endpoint. + /** + * @return The WebSocket close code sent by the remote endpoint. + */ + close::status::value get_remote_close_code() const { + return m_remote_close_code; + } + + /// Get the WebSocket close reason sent by the remote endpoint. + /** + * @return The WebSocket close reason sent by the remote endpoint. + */ + std::string const & get_remote_close_reason() const { + return m_remote_close_reason; + } + + /// Get the internal error code for a closed/failed connection + /** + * Retrieves a machine readable detailed error code indicating the reason + * that the connection was closed or failed. Valid only after the close or + * fail handler is called. + * + * @return Error code indicating the reason the connection was closed or + * failed + */ + lib::error_code get_ec() const { + return m_ec; + } + + /// Get a message buffer + /** + * Warning: The API related to directly sending message buffers may change + * before the 1.0 release. If you plan to use it, please keep an eye on any + * breaking changes notifications in future release notes. Also if you have + * any feedback about usage and capabilities now is a great time to provide + * it. + * + * Message buffers are used to store message payloads and other message + * metadata. + * + * The size parameter is a hint only. Your final payload does not need to + * match it. There may be some performance benefits if the initial size + * guess is equal to or slightly higher than the final payload size. + * + * @param op The opcode for the new message + * @param size A hint to optimize the initial allocation of payload space. + * @return A new message buffer + */ + message_ptr get_message(websocketpp::frame::opcode::value op, size_t size) + const + { + return m_msg_manager->get_message(op, size); + } + + //////////////////////////////////////////////////////////////////////// + // The remaining public member functions are for internal/policy use // + // only. Do not call from application code unless you understand what // + // you are doing. // + //////////////////////////////////////////////////////////////////////// + + + + void read_handshake(size_t num_bytes); + + void handle_read_handshake(lib::error_code const & ec, + size_t bytes_transferred); + void handle_read_http_response(lib::error_code const & ec, + size_t bytes_transferred); + + + void handle_write_http_response(lib::error_code const & ec); + void handle_send_http_request(lib::error_code const & ec); + + void handle_open_handshake_timeout(lib::error_code const & ec); + void handle_close_handshake_timeout(lib::error_code const & ec); + + void handle_read_frame(lib::error_code const & ec, size_t bytes_transferred); + void read_frame(); + + /// Get array of WebSocket protocol versions that this connection supports. + std::vector const & get_supported_versions() const; + + /// Sets the handler for a terminating connection. Should only be used + /// internally by the endpoint class. + void set_termination_handler(termination_handler new_handler); + + void terminate(lib::error_code const & ec); + void handle_terminate(terminate_status tstat, lib::error_code const & ec); + + /// Checks if there are frames in the send queue and if there are sends one + /** + * \todo unit tests + * + * This method locks the m_write_lock mutex + */ + void write_frame(); + + /// Process the results of a frame write operation and start the next write + /** + * \todo unit tests + * + * This method locks the m_write_lock mutex + * + * @param terminate Whether or not to terminate the connection upon + * completion of this write. + * + * @param ec A status code from the transport layer, zero on success, + * non-zero otherwise. + */ + void handle_write_frame(lib::error_code const & ec); +// protected: + // This set of methods would really like to be protected, but doing so + // requires that the endpoint be able to friend the connection. This is + // allowed with C++11, but not prior versions + + /// Start the connection state machine + void start(); + + /// Set Connection Handle + /** + * The connection handle is a token that can be shared outside the + * WebSocket++ core for the purposes of identifying a connection and + * sending it messages. + * + * @param hdl A connection_hdl that the connection will use to refer + * to itself. + */ + void set_handle(connection_hdl hdl) { + m_connection_hdl = hdl; + transport_con_type::set_handle(hdl); + } +protected: + void handle_transport_init(lib::error_code const & ec); + + /// Set m_processor based on information in m_request. Set m_response + /// status and return an error code indicating status. + lib::error_code initialize_processor(); + + /// Perform WebSocket handshake validation of m_request using m_processor. + /// set m_response and return an error code indicating status. + lib::error_code process_handshake_request(); +private: + + + /// Completes m_response, serializes it, and sends it out on the wire. + void write_http_response(lib::error_code const & ec); + + /// Sends an opening WebSocket connect request + void send_http_request(); + + /// Alternate path for write_http_response in error conditions + void write_http_response_error(lib::error_code const & ec); + + /// Process control message + /** + * + */ + void process_control_frame(message_ptr msg); + + /// Send close acknowledgement + /** + * If no arguments are present no close code/reason will be specified. + * + * Note: the close code/reason values provided here may be overrided by + * other settings (such as silent close). + * + * @param code The close code to send + * @param reason The close reason to send + * @return A status code, zero on success, non-zero otherwise + */ + lib::error_code send_close_ack(close::status::value code = + close::status::blank, std::string const & reason = std::string()); + + /// Send close frame + /** + * If no arguments are present no close code/reason will be specified. + * + * Note: the close code/reason values provided here may be overrided by + * other settings (such as silent close). + * + * The ack flag determines what to do in the case of a blank status and + * whether or not to terminate the TCP connection after sending it. + * + * @param code The close code to send + * @param reason The close reason to send + * @param ack Whether or not this is an acknowledgement close frame + * @return A status code, zero on success, non-zero otherwise + */ + lib::error_code send_close_frame(close::status::value code = + close::status::blank, std::string const & reason = std::string(), bool ack = false, + bool terminal = false); + + /// Get a pointer to a new WebSocket protocol processor for a given version + /** + * @param version Version number of the WebSocket protocol to get a + * processor for. Negative values indicate invalid/unknown versions and will + * always return a null ptr + * + * @return A shared_ptr to a new instance of the appropriate processor or a + * null ptr if there is no installed processor that matches the version + * number. + */ + processor_ptr get_processor(int version) const; + + /// Add a message to the write queue + /** + * Adds a message to the write queue and updates any associated shared state + * + * Must be called while holding m_write_lock + * + * @todo unit tests + * + * @param msg The message to push + */ + void write_push(message_ptr msg); + + /// Pop a message from the write queue + /** + * Removes and returns a message from the write queue and updates any + * associated shared state. + * + * Must be called while holding m_write_lock + * + * @todo unit tests + * + * @return the message_ptr at the front of the queue + */ + message_ptr write_pop(); + + /// Prints information about the incoming connection to the access log + /** + * Prints information about the incoming connection to the access log. + * Includes: connection type, websocket version, remote endpoint, user agent + * path, status code. + */ + void log_open_result(); + + /// Prints information about a connection being closed to the access log + /** + * Includes: local and remote close codes and reasons + */ + void log_close_result(); + + /// Prints information about a connection being failed to the access log + /** + * Includes: error code and message for why it was failed + */ + void log_fail_result(); + + /// Prints information about HTTP connections + /** + * Includes: TODO + */ + void log_http_result(); + + /// Prints information about an arbitrary error code on the specified channel + template + void log_err(log::level l, char const * msg, error_type const & ec) { + std::stringstream s; + s << msg << " error: " << ec << " (" << ec.message() << ")"; + m_elog->write(l, s.str()); + } + + // internal handler functions + read_handler m_handle_read_frame; + write_frame_handler m_write_frame_handler; + + // static settings + std::string const m_user_agent; + + /// Pointer to the connection handle + connection_hdl m_connection_hdl; + + /// Handler objects + 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; + + /// constant values + long m_open_handshake_timeout_dur; + long m_close_handshake_timeout_dur; + long m_pong_timeout_dur; + size_t m_max_message_size; + + /// External connection state + /** + * Lock: m_connection_state_lock + */ + session::state::value m_state; + + /// Internal connection state + /** + * Lock: m_connection_state_lock + */ + istate_type m_internal_state; + + mutable mutex_type m_connection_state_lock; + + /// The lock used to protect the message queue + /** + * Serializes access to the write queue as well as shared state within the + * processor. + */ + mutex_type m_write_lock; + + // connection resources + char m_buf[config::connection_read_buffer_size]; + size_t m_buf_cursor; + termination_handler m_termination_handler; + con_msg_manager_ptr m_msg_manager; + timer_ptr m_handshake_timer; + timer_ptr m_ping_timer; + + /// @todo this is not memory efficient. this value is not used after the + /// handshake. + std::string m_handshake_buffer; + + /// Pointer to the processor object for this connection + /** + * The processor provides functionality that is specific to the WebSocket + * protocol version that the client has negotiated. It also contains all of + * the state necessary to encode and decode the incoming and outgoing + * WebSocket byte streams + * + * Use of the prepare_data_frame method requires lock: m_write_lock + */ + processor_ptr m_processor; + + /// Queue of unsent outgoing messages + /** + * Lock: m_write_lock + */ + std::queue m_send_queue; + + /// Size in bytes of the outstanding payloads in the write queue + /** + * Lock: m_write_lock + */ + size_t m_send_buffer_size; + + /// buffer holding the various parts of the current message being writen + /** + * Lock m_write_lock + */ + std::vector m_send_buffer; + + /// a list of pointers to hold on to the messages being written to keep them + /// from going out of scope before the write is complete. + std::vector m_current_msgs; + + /// True if there is currently an outstanding transport write + /** + * Lock m_write_lock + */ + bool m_write_flag; + + /// True if this connection is presently reading new data + bool m_read_flag; + + // connection data + request_type m_request; + response_type m_response; + uri_ptr m_uri; + std::string m_subprotocol; + + // connection data that might not be necessary to keep around for the life + // of the whole connection. + std::vector m_requested_subprotocols; + + bool const m_is_server; + const lib::shared_ptr m_alog; + const lib::shared_ptr m_elog; + + rng_type & m_rng; + + // Close state + /// Close code that was sent on the wire by this endpoint + close::status::value m_local_close_code; + + /// Close reason that was sent on the wire by this endpoint + std::string m_local_close_reason; + + /// Close code that was received on the wire from the remote endpoint + close::status::value m_remote_close_code; + + /// Close reason that was received on the wire from the remote endpoint + std::string m_remote_close_reason; + + /// Detailed internal error code + lib::error_code m_ec; + + /// A flag that gets set once it is determined that the connection is an + /// HTTP connection and not a WebSocket one. + bool m_is_http; + + /// A flag that gets set when the completion of an http connection is + /// deferred until later. + session::http_state::value m_http_state; + + bool m_was_clean; +}; + +} // namespace websocketpp + +#include + +#endif // WEBSOCKETPP_CONNECTION_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/connection_base.hpp b/thirdparty/websocketpp/include/websocketpp/connection_base.hpp index 5515898..2e70096 100644 --- a/thirdparty/websocketpp/include/websocketpp/connection_base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/connection_base.hpp @@ -1,38 +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 +/* + * 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 diff --git a/thirdparty/websocketpp/include/websocketpp/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/endpoint.hpp index 00fee50..c124b1d 100644 --- a/thirdparty/websocketpp/include/websocketpp/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/endpoint.hpp @@ -1,700 +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 - -#include -#include - -#include - -namespace websocketpp { - -/// Creates and manages connections associated with a WebSocket endpoint -template -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 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() {} - - #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( - 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 m_alog; - lib::shared_ptr 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 - -#endif // WEBSOCKETPP_ENDPOINT_HPP +/* + * 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 + +#include +#include + +#include + +namespace websocketpp { + +/// Creates and manages connections associated with a WebSocket endpoint +template +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 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() {} + + #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( + 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 m_alog; + lib::shared_ptr 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 + +#endif // WEBSOCKETPP_ENDPOINT_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/endpoint_base.hpp b/thirdparty/websocketpp/include/websocketpp/endpoint_base.hpp index 6ffb37e..1ad1a44 100644 --- a/thirdparty/websocketpp/include/websocketpp/endpoint_base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/endpoint_base.hpp @@ -1,38 +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 +/* + * 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 diff --git a/thirdparty/websocketpp/include/websocketpp/error.hpp b/thirdparty/websocketpp/include/websocketpp/error.hpp index c336bb0..562fb6e 100644 --- a/thirdparty/websocketpp/include/websocketpp/error.hpp +++ b/thirdparty/websocketpp/include/websocketpp/error.hpp @@ -1,277 +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 -#include -#include - -#include -#include - -namespace websocketpp { - -/// Combination error code / string type for returning two values -typedef std::pair 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(e), get_category()); -} - -} // namespace error -} // namespace websocketpp - -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - 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 +/* + * 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 +#include +#include + +#include +#include + +namespace websocketpp { + +/// Combination error code / string type for returning two values +typedef std::pair 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(e), get_category()); +} + +} // namespace error +} // namespace websocketpp + +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + 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 diff --git a/thirdparty/websocketpp/include/websocketpp/extensions/extension.hpp b/thirdparty/websocketpp/include/websocketpp/extensions/extension.hpp index cdcfba5..f5fbd9f 100644 --- a/thirdparty/websocketpp/include/websocketpp/extensions/extension.hpp +++ b/thirdparty/websocketpp/include/websocketpp/extensions/extension.hpp @@ -1,102 +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 -#include - -#include -#include - -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(e), get_category()); -} - -} // namespace error -} // namespace extensions -} // namespace websocketpp - -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum - -{ - static const bool value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif // WEBSOCKETPP_EXTENSION_HPP +/* + * 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 +#include + +#include +#include + +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(e), get_category()); +} + +} // namespace error +} // namespace extensions +} // namespace websocketpp + +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum + +{ + static const bool value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_EXTENSION_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/disabled.hpp b/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/disabled.hpp index 2063b99..6573095 100644 --- a/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/disabled.hpp +++ b/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/disabled.hpp @@ -1,129 +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 -#include -#include - -#include -#include - -#include -#include -#include - -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 -class disabled { - typedef std::pair 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 +/* + * 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 +#include +#include + +#include +#include + +#include +#include +#include + +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 +class disabled { + typedef std::pair 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 diff --git a/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/enabled.hpp b/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/enabled.hpp index 1ad99cc..d05403a 100644 --- a/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/thirdparty/websocketpp/include/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -1,817 +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 -#include -#include -#include -#include -#include - -#include - -#include "zlib.h" - -#include -#include -#include - -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(e), get_category()); -} - -} // namespace error -} // namespace permessage_deflate -} // namespace extensions -} // namespace websocketpp - -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum - -{ - 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 -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(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(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(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 +/* + * 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 +#include +#include +#include +#include +#include + +#include + +#include "zlib.h" + +#include +#include +#include + +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(e), get_category()); +} + +} // namespace error +} // namespace permessage_deflate +} // namespace extensions +} // namespace websocketpp + +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum + +{ + 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 +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(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(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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/frame.hpp b/thirdparty/websocketpp/include/websocketpp/frame.hpp index fb1b840..18a990b 100644 --- a/thirdparty/websocketpp/include/websocketpp/frame.hpp +++ b/thirdparty/websocketpp/include/websocketpp/frame.hpp @@ -1,864 +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 -#include - -#include -#include - -#include - -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(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 -void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type - const & key, size_t key_offset = 0); -template -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(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(key.i); - - if (sizeof(size_t) == 8) { - uint64_t high_bits = static_cast(key.i); - return static_cast((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 -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 -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(input); - size_t* output_word = reinterpret_cast(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(input); - size_t * output_word = reinterpret_cast(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(&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 +/* + * 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 +#include + +#include +#include + +#include + +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(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 +void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type + const & key, size_t key_offset = 0); +template +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(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(key.i); + + if (sizeof(size_t) == 8) { + uint64_t high_bits = static_cast(key.i); + return static_cast((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 +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 +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(input); + size_t* output_word = reinterpret_cast(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(input); + size_t * output_word = reinterpret_cast(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(&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 diff --git a/thirdparty/websocketpp/include/websocketpp/http/constants.hpp b/thirdparty/websocketpp/include/websocketpp/http/constants.hpp index ce0cd37..f946cb3 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/constants.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/constants.hpp @@ -1,308 +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 -#include -#include -#include -#include - -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 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 > 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 +/* + * 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 +#include +#include +#include +#include + +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 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 > 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 diff --git a/thirdparty/websocketpp/include/websocketpp/http/impl/parser.hpp b/thirdparty/websocketpp/include/websocketpp/http/impl/parser.hpp index eea5893..fd24adb 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/impl/parser.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/impl/parser.hpp @@ -1,200 +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 -#include -#include -#include -#include - -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 +/* + * 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 +#include +#include +#include +#include + +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 diff --git a/thirdparty/websocketpp/include/websocketpp/http/impl/request.hpp b/thirdparty/websocketpp/include/websocketpp/http/impl/request.hpp index 1a2b5bf..311a620 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/impl/request.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/impl/request.hpp @@ -1,191 +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 -#include -#include - -#include - -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(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(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 +/* + * 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 +#include +#include + +#include + +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(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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/http/impl/response.hpp b/thirdparty/websocketpp/include/websocketpp/http/impl/response.hpp index 714b94d..4400cda 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/impl/response.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/impl/response.hpp @@ -1,266 +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 -#include -#include -#include - -#include - -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(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(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(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 +/* + * 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 +#include +#include +#include + +#include + +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(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(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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/http/parser.hpp b/thirdparty/websocketpp/include/websocketpp/http/parser.hpp index 2e5b72e..9d309ec 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/parser.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/parser.hpp @@ -1,629 +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 -#include -#include -#include - -#include -#include - -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 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 -std::pair 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 -std::pair 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 -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(*(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 -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 -InputIterator extract_attributes(InputIterator begin, InputIterator end, - attribute_list & attributes) -{ - InputIterator cursor; - bool first = true; - - if (begin == end) { - return begin; - } - - cursor = begin; - std::pair 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 -InputIterator extract_parameters(InputIterator begin, InputIterator end, - parameter_list ¶meters) -{ - InputIterator cursor; - - if (begin == end) { - // error: expected non-zero length range - return begin; - } - - cursor = begin; - std::pair 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 - -#endif // HTTP_PARSER_HPP +/* + * 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 +#include +#include +#include + +#include +#include + +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 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 +std::pair 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 +std::pair 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 +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(*(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 +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 +InputIterator extract_attributes(InputIterator begin, InputIterator end, + attribute_list & attributes) +{ + InputIterator cursor; + bool first = true; + + if (begin == end) { + return begin; + } + + cursor = begin; + std::pair 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 +InputIterator extract_parameters(InputIterator begin, InputIterator end, + parameter_list ¶meters) +{ + InputIterator cursor; + + if (begin == end) { + // error: expected non-zero length range + return begin; + } + + cursor = begin; + std::pair 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 + +#endif // HTTP_PARSER_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/http/request.hpp b/thirdparty/websocketpp/include/websocketpp/http/request.hpp index a3065e5..3355c99 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/request.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/request.hpp @@ -1,124 +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 - -#include -#include - -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 ptr; - - request() - : m_buf(lib::make_shared()) - , 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 m_buf; - std::string m_method; - std::string m_uri; - bool m_ready; -}; - -} // namespace parser -} // namespace http -} // namespace websocketpp - -#include - -#endif // HTTP_PARSER_REQUEST_HPP +/* + * 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 + +#include +#include + +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 ptr; + + request() + : m_buf(lib::make_shared()) + , 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 m_buf; + std::string m_method; + std::string m_uri; + bool m_ready; +}; + +} // namespace parser +} // namespace http +} // namespace websocketpp + +#include + +#endif // HTTP_PARSER_REQUEST_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/http/response.hpp b/thirdparty/websocketpp/include/websocketpp/http/response.hpp index 36731d2..e724a3d 100644 --- a/thirdparty/websocketpp/include/websocketpp/http/response.hpp +++ b/thirdparty/websocketpp/include/websocketpp/http/response.hpp @@ -1,188 +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 -#include - -#include - -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 ptr; - - response() - : m_read(0) - , m_buf(lib::make_shared()) - , 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 m_buf; - status_code::value m_status_code; - state m_state; - -}; - -} // namespace parser -} // namespace http -} // namespace websocketpp - -#include - -#endif // HTTP_PARSER_RESPONSE_HPP +/* + * 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 +#include + +#include + +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 ptr; + + response() + : m_read(0) + , m_buf(lib::make_shared()) + , 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 m_buf; + status_code::value m_status_code; + state m_state; + +}; + +} // namespace parser +} // namespace http +} // namespace websocketpp + +#include + +#endif // HTTP_PARSER_RESPONSE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/impl/connection_impl.hpp b/thirdparty/websocketpp/include/websocketpp/impl/connection_impl.hpp index d635817..bf88c95 100644 --- a/thirdparty/websocketpp/include/websocketpp/impl/connection_impl.hpp +++ b/thirdparty/websocketpp/include/websocketpp/impl/connection_impl.hpp @@ -1,2375 +1,2375 @@ -/* - * 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_IMPL_HPP -#define WEBSOCKETPP_CONNECTION_IMPL_HPP - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace websocketpp { - -namespace istate = session::internal_state; - -template -void connection::set_termination_handler( - termination_handler new_handler) -{ - m_alog->write(log::alevel::devel, - "connection set_termination_handler"); - - //scoped_lock_type lock(m_connection_state_lock); - - m_termination_handler = new_handler; -} - -template -std::string const & connection::get_origin() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_processor->get_origin(m_request); -} - -template -size_t connection::get_buffered_amount() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_send_buffer_size; -} - -template -session::state::value connection::get_state() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_state; -} - -template -lib::error_code connection::send(std::string const & payload, - frame::opcode::value op) -{ - message_ptr msg = m_msg_manager->get_message(op,payload.size()); - msg->append_payload(payload); - msg->set_compressed(true); - - return send(msg); -} - -template -lib::error_code connection::send(void const * payload, size_t len, - frame::opcode::value op) -{ - message_ptr msg = m_msg_manager->get_message(op,len); - msg->append_payload(payload,len); - - return send(msg); -} - -template -lib::error_code connection::send(typename config::message_type::ptr msg) -{ - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection send"); - } - - { - scoped_lock_type lock(m_connection_state_lock); - if (m_state != session::state::open) { - return error::make_error_code(error::invalid_state); - } - } - - message_ptr outgoing_msg; - bool needs_writing = false; - - if (msg->get_prepared()) { - outgoing_msg = msg; - - scoped_lock_type lock(m_write_lock); - write_push(outgoing_msg); - needs_writing = !m_write_flag && !m_send_queue.empty(); - } else { - outgoing_msg = m_msg_manager->get_message(); - - if (!outgoing_msg) { - return error::make_error_code(error::no_outgoing_buffers); - } - - scoped_lock_type lock(m_write_lock); - lib::error_code ec = m_processor->prepare_data_frame(msg,outgoing_msg); - - if (ec) { - return ec; - } - - write_push(outgoing_msg); - needs_writing = !m_write_flag && !m_send_queue.empty(); - } - - if (needs_writing) { - transport_con_type::dispatch(lib::bind( - &type::write_frame, - type::get_shared() - )); - } - - return lib::error_code(); -} - -template -void connection::ping(std::string const& payload, lib::error_code& ec) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection ping"); - } - - { - scoped_lock_type lock(m_connection_state_lock); - if (m_state != session::state::open) { - std::stringstream ss; - ss << "connection::ping called from invalid state " << m_state; - m_alog->write(log::alevel::devel,ss.str()); - ec = error::make_error_code(error::invalid_state); - return; - } - } - - message_ptr msg = m_msg_manager->get_message(); - if (!msg) { - ec = error::make_error_code(error::no_outgoing_buffers); - return; - } - - ec = m_processor->prepare_ping(payload,msg); - if (ec) {return;} - - // set ping timer if we are listening for one - if (m_pong_timeout_handler) { - // Cancel any existing timers - if (m_ping_timer) { - m_ping_timer->cancel(); - } - - if (m_pong_timeout_dur > 0) { - m_ping_timer = transport_con_type::set_timer( - m_pong_timeout_dur, - lib::bind( - &type::handle_pong_timeout, - type::get_shared(), - payload, - lib::placeholders::_1 - ) - ); - } - - if (!m_ping_timer) { - // Our transport doesn't support timers - m_elog->write(log::elevel::warn,"Warning: a pong_timeout_handler is \ - set but the transport in use does not support timeouts."); - } - } - - bool needs_writing = false; - { - scoped_lock_type lock(m_write_lock); - write_push(msg); - needs_writing = !m_write_flag && !m_send_queue.empty(); - } - - if (needs_writing) { - transport_con_type::dispatch(lib::bind( - &type::write_frame, - type::get_shared() - )); - } - - ec = lib::error_code(); -} - -template -void connection::ping(std::string const & payload) { - lib::error_code ec; - ping(payload,ec); - if (ec) { - throw exception(ec); - } -} - -template -void connection::handle_pong_timeout(std::string payload, - lib::error_code const & ec) -{ - if (ec) { - if (ec == transport::error::operation_aborted) { - // ignore, this is expected - return; - } - - m_elog->write(log::elevel::devel,"pong_timeout error: "+ec.message()); - return; - } - - if (m_pong_timeout_handler) { - m_pong_timeout_handler(m_connection_hdl,payload); - } -} - -template -void connection::pong(std::string const& payload, lib::error_code& ec) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection pong"); - } - - { - scoped_lock_type lock(m_connection_state_lock); - if (m_state != session::state::open) { - std::stringstream ss; - ss << "connection::pong called from invalid state " << m_state; - m_alog->write(log::alevel::devel,ss.str()); - ec = error::make_error_code(error::invalid_state); - return; - } - } - - message_ptr msg = m_msg_manager->get_message(); - if (!msg) { - ec = error::make_error_code(error::no_outgoing_buffers); - return; - } - - ec = m_processor->prepare_pong(payload,msg); - if (ec) {return;} - - bool needs_writing = false; - { - scoped_lock_type lock(m_write_lock); - write_push(msg); - needs_writing = !m_write_flag && !m_send_queue.empty(); - } - - if (needs_writing) { - transport_con_type::dispatch(lib::bind( - &type::write_frame, - type::get_shared() - )); - } - - ec = lib::error_code(); -} - -template -void connection::pong(std::string const & payload) { - lib::error_code ec; - pong(payload,ec); - if (ec) { - throw exception(ec); - } -} - -template -void connection::close(close::status::value const code, - std::string const & reason, lib::error_code & ec) -{ - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection close"); - } - - // Truncate reason to maximum size allowable in a close frame. - std::string tr(reason,0,std::min(reason.size(), - frame::limits::close_reason_size)); - - scoped_lock_type lock(m_connection_state_lock); - - if (m_state != session::state::open) { - ec = error::make_error_code(error::invalid_state); - return; - } - - ec = this->send_close_frame(code,tr,false,close::status::terminal(code)); -} - -template -void connection::close(close::status::value const code, - std::string const & reason) -{ - lib::error_code ec; - close(code,reason,ec); - if (ec) { - throw exception(ec); - } -} - -/// Trigger the on_interrupt handler -/** - * This is thread safe if the transport is thread safe - */ -template -lib::error_code connection::interrupt() { - m_alog->write(log::alevel::devel,"connection connection::interrupt"); - return transport_con_type::interrupt( - lib::bind( - &type::handle_interrupt, - type::get_shared() - ) - ); -} - - -template -void connection::handle_interrupt() { - if (m_interrupt_handler) { - m_interrupt_handler(m_connection_hdl); - } -} - -template -lib::error_code connection::pause_reading() { - m_alog->write(log::alevel::devel,"connection connection::pause_reading"); - return transport_con_type::dispatch( - lib::bind( - &type::handle_pause_reading, - type::get_shared() - ) - ); -} - -/// Pause reading handler. Not safe to call directly -template -void connection::handle_pause_reading() { - m_alog->write(log::alevel::devel,"connection connection::handle_pause_reading"); - m_read_flag = false; -} - -template -lib::error_code connection::resume_reading() { - m_alog->write(log::alevel::devel,"connection connection::resume_reading"); - return transport_con_type::dispatch( - lib::bind( - &type::handle_resume_reading, - type::get_shared() - ) - ); -} - -/// Resume reading helper method. Not safe to call directly -template -void connection::handle_resume_reading() { - m_read_flag = true; - read_frame(); -} - - - - - - - - - - - -template -bool connection::get_secure() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_uri->get_secure(); -} - -template -std::string const & connection::get_host() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_uri->get_host(); -} - -template -std::string const & connection::get_resource() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_uri->get_resource(); -} - -template -uint16_t connection::get_port() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_uri->get_port(); -} - -template -uri_ptr connection::get_uri() const { - //scoped_lock_type lock(m_connection_state_lock); - return m_uri; -} - -template -void connection::set_uri(uri_ptr uri) { - //scoped_lock_type lock(m_connection_state_lock); - m_uri = uri; -} - - - - - - -template -std::string const & connection::get_subprotocol() const { - return m_subprotocol; -} - -template -std::vector const & -connection::get_requested_subprotocols() const { - return m_requested_subprotocols; -} - -template -void connection::add_subprotocol(std::string const & value, - lib::error_code & ec) -{ - if (m_is_server) { - ec = error::make_error_code(error::client_only); - return; - } - - // If the value is empty or has a non-RFC2616 token character it is invalid. - if (value.empty() || std::find_if(value.begin(),value.end(), - http::is_not_token_char) != value.end()) - { - ec = error::make_error_code(error::invalid_subprotocol); - return; - } - - m_requested_subprotocols.push_back(value); -} - -template -void connection::add_subprotocol(std::string const & value) { - lib::error_code ec; - this->add_subprotocol(value,ec); - if (ec) { - throw exception(ec); - } -} - - -template -void connection::select_subprotocol(std::string const & value, - lib::error_code & ec) -{ - if (!m_is_server) { - ec = error::make_error_code(error::server_only); - return; - } - - if (value.empty()) { - ec = lib::error_code(); - return; - } - - std::vector::iterator it; - - it = std::find(m_requested_subprotocols.begin(), - m_requested_subprotocols.end(), - value); - - if (it == m_requested_subprotocols.end()) { - ec = error::make_error_code(error::unrequested_subprotocol); - return; - } - - m_subprotocol = value; -} - -template -void connection::select_subprotocol(std::string const & value) { - lib::error_code ec; - this->select_subprotocol(value,ec); - if (ec) { - throw exception(ec); - } -} - - -template -std::string const & -connection::get_request_header(std::string const & key) const { - return m_request.get_header(key); -} - -template -std::string const & -connection::get_request_body() const { - return m_request.get_body(); -} - -template -std::string const & -connection::get_response_header(std::string const & key) const { - return m_response.get_header(key); -} - -// TODO: EXCEPTION_FREE -template -void connection::set_status(http::status_code::value code) -{ - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw exception("Call to set_status from invalid state", - error::make_error_code(error::invalid_state)); - } - m_response.set_status(code); -} - -// TODO: EXCEPTION_FREE -template -void connection::set_status(http::status_code::value code, - std::string const & msg) -{ - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw exception("Call to set_status from invalid state", - error::make_error_code(error::invalid_state)); - } - - m_response.set_status(code,msg); -} - -// TODO: EXCEPTION_FREE -template -void connection::set_body(std::string const & value) { - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw exception("Call to set_status from invalid state", - error::make_error_code(error::invalid_state)); - } - - m_response.set_body(value); -} - -// TODO: EXCEPTION_FREE -template -void connection::append_header(std::string const & key, - std::string const & val) -{ - if (m_is_server) { - if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { - // we are setting response headers for an incoming server connection - m_response.append_header(key,val); - } else { - throw exception("Call to append_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } else { - if (m_internal_state == istate::USER_INIT) { - // we are setting initial headers for an outgoing client connection - m_request.append_header(key,val); - } else { - throw exception("Call to append_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } -} - -// TODO: EXCEPTION_FREE -template -void connection::replace_header(std::string const & key, - std::string const & val) -{ - if (m_is_server) { - if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { - // we are setting response headers for an incoming server connection - m_response.replace_header(key,val); - } else { - throw exception("Call to replace_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } else { - if (m_internal_state == istate::USER_INIT) { - // we are setting initial headers for an outgoing client connection - m_request.replace_header(key,val); - } else { - throw exception("Call to replace_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } -} - -// TODO: EXCEPTION_FREE -template -void connection::remove_header(std::string const & key) -{ - if (m_is_server) { - if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { - // we are setting response headers for an incoming server connection - m_response.remove_header(key); - } else { - throw exception("Call to remove_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } else { - if (m_internal_state == istate::USER_INIT) { - // we are setting initial headers for an outgoing client connection - m_request.remove_header(key); - } else { - throw exception("Call to remove_header from invalid state", - error::make_error_code(error::invalid_state)); - } - } -} - -/// Defer HTTP Response until later -/** - * Used in the http handler to defer the HTTP response for this connection - * until later. Handshake timers will be canceled and the connection will be - * left open until `send_http_response` or an equivalent is called. - * - * Warning: deferred connections won't time out and as a result can tie up - * resources. - * - * @return A status code, zero on success, non-zero otherwise - */ -template -lib::error_code connection::defer_http_response() { - // Cancel handshake timer, otherwise the connection will time out and we'll - // close the connection before the app has a chance to send a response. - if (m_handshake_timer) { - m_handshake_timer->cancel(); - m_handshake_timer.reset(); - } - - // Do something to signal deferral - m_http_state = session::http_state::deferred; - - return lib::error_code(); -} - -/// 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. - * - * @since 0.6.0 - * - * @param ec A status code, zero on success, non-zero otherwise - */ -template -void connection::send_http_response(lib::error_code & ec) { - { - scoped_lock_type lock(m_connection_state_lock); - if (m_http_state != session::http_state::deferred) { - ec = error::make_error_code(error::invalid_state); - return; - } - - m_http_state = session::http_state::body_written; - } - - this->write_http_response(lib::error_code()); - ec = lib::error_code(); -} - -template -void connection::send_http_response() { - lib::error_code ec; - this->send_http_response(ec); - if (ec) { - throw exception(ec); - } -} - - - - -/******** logic thread ********/ - -template -void connection::start() { - m_alog->write(log::alevel::devel,"connection start"); - - if (m_internal_state != istate::USER_INIT) { - m_alog->write(log::alevel::devel,"Start called in invalid state"); - this->terminate(error::make_error_code(error::invalid_state)); - return; - } - - m_internal_state = istate::TRANSPORT_INIT; - - // Depending on how the transport implements init this function may return - // immediately and call handle_transport_init later or call - // handle_transport_init from this function. - transport_con_type::init( - lib::bind( - &type::handle_transport_init, - type::get_shared(), - lib::placeholders::_1 - ) - ); -} - -template -void connection::handle_transport_init(lib::error_code const & ec) { - m_alog->write(log::alevel::devel,"connection handle_transport_init"); - - lib::error_code ecm = ec; - - if (m_internal_state != istate::TRANSPORT_INIT) { - m_alog->write(log::alevel::devel, - "handle_transport_init must be called from transport init state"); - ecm = error::make_error_code(error::invalid_state); - } - - if (ecm) { - std::stringstream s; - s << "handle_transport_init received error: "<< ecm.message(); - m_elog->write(log::elevel::rerror,s.str()); - - this->terminate(ecm); - return; - } - - // At this point the transport is ready to read and write bytes. - if (m_is_server) { - m_internal_state = istate::READ_HTTP_REQUEST; - this->read_handshake(1); - } else { - // We are a client. Set the processor to the version specified in the - // config file and send a handshake request. - m_internal_state = istate::WRITE_HTTP_REQUEST; - m_processor = get_processor(config::client_version); - this->send_http_request(); - } -} - -template -void connection::read_handshake(size_t num_bytes) { - m_alog->write(log::alevel::devel,"connection read_handshake"); - - if (m_open_handshake_timeout_dur > 0) { - m_handshake_timer = transport_con_type::set_timer( - m_open_handshake_timeout_dur, - lib::bind( - &type::handle_open_handshake_timeout, - type::get_shared(), - lib::placeholders::_1 - ) - ); - } - - transport_con_type::async_read_at_least( - num_bytes, - m_buf, - config::connection_read_buffer_size, - lib::bind( - &type::handle_read_handshake, - type::get_shared(), - lib::placeholders::_1, - lib::placeholders::_2 - ) - ); -} - -// All exit paths for this function need to call write_http_response() or submit -// a new read request with this function as the handler. -template -void connection::handle_read_handshake(lib::error_code const & ec, - size_t bytes_transferred) -{ - m_alog->write(log::alevel::devel,"connection handle_read_handshake"); - - lib::error_code ecm = ec; - - if (!ecm) { - scoped_lock_type lock(m_connection_state_lock); - - if (m_state == session::state::connecting) { - if (m_internal_state != istate::READ_HTTP_REQUEST) { - ecm = error::make_error_code(error::invalid_state); - } - } else if (m_state == session::state::closed) { - // The connection was canceled while the response was being sent, - // usually by the handshake timer. This is basically expected - // (though hopefully rare) and there is nothing we can do so ignore. - m_alog->write(log::alevel::devel, - "handle_read_handshake invoked after connection was closed"); - return; - } else { - ecm = error::make_error_code(error::invalid_state); - } - } - - if (ecm) { - if (ecm == transport::error::eof && m_state == session::state::closed) { - // we expect to get eof if the connection is closed already - m_alog->write(log::alevel::devel, - "got (expected) eof/state error from closed con"); - return; - } - - log_err(log::elevel::rerror,"handle_read_handshake",ecm); - this->terminate(ecm); - return; - } - - // Boundaries checking. TODO: How much of this should be done? - if (bytes_transferred > config::connection_read_buffer_size) { - m_elog->write(log::elevel::fatal,"Fatal boundaries checking error."); - this->terminate(make_error_code(error::general)); - return; - } - - size_t bytes_processed = 0; - try { - bytes_processed = m_request.consume(m_buf,bytes_transferred); - } catch (http::exception &e) { - // All HTTP exceptions will result in this request failing and an error - // response being returned. No more bytes will be read in this con. - m_response.set_status(e.m_error_code,e.m_error_msg); - this->write_http_response_error(error::make_error_code(error::http_parse_error)); - return; - } - - // More paranoid boundaries checking. - // TODO: Is this overkill? - if (bytes_processed > bytes_transferred) { - m_elog->write(log::elevel::fatal,"Fatal boundaries checking error."); - this->terminate(make_error_code(error::general)); - return; - } - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "bytes_transferred: " << bytes_transferred - << " bytes, bytes processed: " << bytes_processed << " bytes"; - m_alog->write(log::alevel::devel,s.str()); - } - - if (m_request.ready()) { - lib::error_code processor_ec = this->initialize_processor(); - if (processor_ec) { - this->write_http_response_error(processor_ec); - return; - } - - if (m_processor && m_processor->get_version() == 0) { - // Version 00 has an extra requirement to read some bytes after the - // handshake - if (bytes_transferred-bytes_processed >= 8) { - m_request.replace_header( - "Sec-WebSocket-Key3", - std::string(m_buf+bytes_processed,m_buf+bytes_processed+8) - ); - bytes_processed += 8; - } else { - // TODO: need more bytes - m_alog->write(log::alevel::devel,"short key3 read"); - m_response.set_status(http::status_code::internal_server_error); - this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3)); - return; - } - } - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,m_request.raw()); - if (!m_request.get_header("Sec-WebSocket-Key3").empty()) { - m_alog->write(log::alevel::devel, - utility::to_hex(m_request.get_header("Sec-WebSocket-Key3"))); - } - } - - // The remaining bytes in m_buf are frame data. Copy them to the - // beginning of the buffer and note the length. They will be read after - // the handshake completes and before more bytes are read. - std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf); - m_buf_cursor = bytes_transferred-bytes_processed; - - - m_internal_state = istate::PROCESS_HTTP_REQUEST; - - // We have the complete request. Process it. - lib::error_code handshake_ec = this->process_handshake_request(); - - // Write a response if this is a websocket connection or if it is an - // HTTP connection for which the response has not been deferred or - // started yet by a different system (i.e. still in init state). - if (!m_is_http || m_http_state == session::http_state::init) { - this->write_http_response(handshake_ec); - } - } else { - // read at least 1 more byte - transport_con_type::async_read_at_least( - 1, - m_buf, - config::connection_read_buffer_size, - lib::bind( - &type::handle_read_handshake, - type::get_shared(), - lib::placeholders::_1, - lib::placeholders::_2 - ) - ); - } -} - -// write_http_response requires the request to be fully read and the connection -// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors -// before the request is fully read (specifically at a point where we aren't -// sure if the hybi00 key3 bytes need to be read). This method sets the correct -// state and calls write_http_response -template -void connection::write_http_response_error(lib::error_code const & ec) { - if (m_internal_state != istate::READ_HTTP_REQUEST) { - m_alog->write(log::alevel::devel, - "write_http_response_error called in invalid state"); - this->terminate(error::make_error_code(error::invalid_state)); - return; - } - - m_internal_state = istate::PROCESS_HTTP_REQUEST; - - this->write_http_response(ec); -} - -// All exit paths for this function need to call write_http_response() or submit -// a new read request with this function as the handler. -template -void connection::handle_read_frame(lib::error_code const & ec, - size_t bytes_transferred) -{ - //m_alog->write(log::alevel::devel,"connection handle_read_frame"); - - lib::error_code ecm = ec; - - if (!ecm && m_internal_state != istate::PROCESS_CONNECTION) { - ecm = error::make_error_code(error::invalid_state); - } - - if (ecm) { - log::level echannel = log::elevel::rerror; - - if (ecm == transport::error::eof) { - if (m_state == session::state::closed) { - // we expect to get eof if the connection is closed already - // just ignore it - m_alog->write(log::alevel::devel,"got eof from closed con"); - return; - } else if (m_state == session::state::closing && !m_is_server) { - // If we are a client we expect to get eof in the closing state, - // this is a signal to terminate our end of the connection after - // the closing handshake - terminate(lib::error_code()); - return; - } - } else if (ecm == error::invalid_state) { - // In general, invalid state errors in the closed state are the - // result of handlers that were in the system already when the state - // changed and should be ignored as they pose no problems and there - // is nothing useful that we can do about them. - if (m_state == session::state::closed) { - m_alog->write(log::alevel::devel, - "handle_read_frame: got invalid istate in closed state"); - return; - } - } else if (ecm == transport::error::action_after_shutdown) { - echannel = log::elevel::info; - } else { - // TODO: more generally should we do something different here in the - // case that m_state is cosed? Are errors after the connection is - // already closed really an rerror? - } - - - - log_err(echannel, "handle_read_frame", ecm); - this->terminate(ecm); - return; - } - - // Boundaries checking. TODO: How much of this should be done? - /*if (bytes_transferred > config::connection_read_buffer_size) { - m_elog->write(log::elevel::fatal,"Fatal boundaries checking error"); - this->terminate(make_error_code(error::general)); - return; - }*/ - - size_t p = 0; - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "p = " << p << " bytes transferred = " << bytes_transferred; - m_alog->write(log::alevel::devel,s.str()); - } - - while (p < bytes_transferred) { - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "calling consume with " << bytes_transferred-p << " bytes"; - m_alog->write(log::alevel::devel,s.str()); - } - - lib::error_code consume_ec; - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "Processing Bytes: " << utility::to_hex(reinterpret_cast(m_buf)+p,bytes_transferred-p); - m_alog->write(log::alevel::devel,s.str()); - } - - p += m_processor->consume( - reinterpret_cast(m_buf)+p, - bytes_transferred-p, - consume_ec - ); - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "bytes left after consume: " << bytes_transferred-p; - m_alog->write(log::alevel::devel,s.str()); - } - if (consume_ec) { - log_err(log::elevel::rerror, "consume", consume_ec); - - if (config::drop_on_protocol_error) { - this->terminate(consume_ec); - return; - } else { - lib::error_code close_ec; - this->close( - processor::error::to_ws(consume_ec), - consume_ec.message(), - close_ec - ); - - if (close_ec) { - log_err(log::elevel::fatal, "Protocol error close frame ", close_ec); - this->terminate(close_ec); - return; - } - } - return; - } - - if (m_processor->ready()) { - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "Complete message received. Dispatching"; - m_alog->write(log::alevel::devel,s.str()); - } - - message_ptr msg = m_processor->get_message(); - - if (!msg) { - m_alog->write(log::alevel::devel, "null message from m_processor"); - } else if (!is_control(msg->get_opcode())) { - // data message, dispatch to user - if (m_state != session::state::open) { - m_elog->write(log::elevel::warn, "got non-close frame while closing"); - } else if (m_message_handler) { - m_message_handler(m_connection_hdl, msg); - } - } else { - process_control_frame(msg); - } - } - } - - read_frame(); -} - -/// Issue a new transport read unless reading is paused. -template -void connection::read_frame() { - if (!m_read_flag) { - return; - } - - transport_con_type::async_read_at_least( - // std::min wont work with undefined static const values. - // TODO: is there a more elegant way to do this? - // Need to determine if requesting 1 byte or the exact number of bytes - // is better here. 1 byte lets us be a bit more responsive at a - // potential expense of additional runs through handle_read_frame - /*(m_processor->get_bytes_needed() > config::connection_read_buffer_size ? - config::connection_read_buffer_size : m_processor->get_bytes_needed())*/ - 1, - m_buf, - config::connection_read_buffer_size, - m_handle_read_frame - ); -} - -template -lib::error_code connection::initialize_processor() { - m_alog->write(log::alevel::devel,"initialize_processor"); - - // if it isn't a websocket handshake nothing to do. - if (!processor::is_websocket_handshake(m_request)) { - return lib::error_code(); - } - - int version = processor::get_websocket_version(m_request); - - if (version < 0) { - m_alog->write(log::alevel::devel, "BAD REQUEST: can't determine version"); - m_response.set_status(http::status_code::bad_request); - return error::make_error_code(error::invalid_version); - } - - m_processor = get_processor(version); - - // if the processor is not null we are done - if (m_processor) { - return lib::error_code(); - } - - // We don't have a processor for this version. Return bad request - // with Sec-WebSocket-Version header filled with values we do accept - m_alog->write(log::alevel::devel, "BAD REQUEST: no processor for version"); - m_response.set_status(http::status_code::bad_request); - - std::stringstream ss; - std::string sep; - std::vector::const_iterator it; - for (it = versions_supported.begin(); it != versions_supported.end(); it++) - { - ss << sep << *it; - sep = ","; - } - - m_response.replace_header("Sec-WebSocket-Version",ss.str()); - return error::make_error_code(error::unsupported_version); -} - -template -lib::error_code connection::process_handshake_request() { - m_alog->write(log::alevel::devel,"process handshake request"); - - if (!processor::is_websocket_handshake(m_request)) { - // this is not a websocket handshake. Process as plain HTTP - m_alog->write(log::alevel::devel,"HTTP REQUEST"); - - // extract URI from request - m_uri = processor::get_uri_from_host( - m_request, - (transport_con_type::is_secure() ? "https" : "http") - ); - - if (!m_uri->get_valid()) { - m_alog->write(log::alevel::devel, "Bad request: failed to parse uri"); - m_response.set_status(http::status_code::bad_request); - return error::make_error_code(error::invalid_uri); - } - - if (m_http_handler) { - m_is_http = true; - m_http_handler(m_connection_hdl); - - if (m_state == session::state::closed) { - return error::make_error_code(error::http_connection_ended); - } - } else { - set_status(http::status_code::upgrade_required); - return error::make_error_code(error::upgrade_required); - } - - return lib::error_code(); - } - - lib::error_code ec = m_processor->validate_handshake(m_request); - - // Validate: make sure all required elements are present. - if (ec){ - // Not a valid handshake request - m_alog->write(log::alevel::devel, "Bad request " + ec.message()); - m_response.set_status(http::status_code::bad_request); - return ec; - } - - // Read extension parameters and set up values necessary for the end user - // to complete extension negotiation. - std::pair neg_results; - neg_results = m_processor->negotiate_extensions(m_request); - - if (neg_results.first == processor::error::make_error_code(processor::error::extension_parse_error)) { - // There was a fatal error in extension parsing that should result in - // a failed connection attempt. - m_elog->write(log::elevel::info, "Bad request: " + neg_results.first.message()); - m_response.set_status(http::status_code::bad_request); - return neg_results.first; - } else if (neg_results.first) { - // There was a fatal error in extension processing that is probably our - // fault. Consider extension negotiation to have failed and continue as - // if extensions were not supported - m_elog->write(log::elevel::info, - "Extension negotiation failed: " + neg_results.first.message()); - } else { - // extension negotiation succeeded, set response header accordingly - // we don't send an empty extensions header because it breaks many - // clients. - if (neg_results.second.size() > 0) { - m_response.replace_header("Sec-WebSocket-Extensions", - neg_results.second); - } - } - - // extract URI from request - m_uri = m_processor->get_uri(m_request); - - - if (!m_uri->get_valid()) { - m_alog->write(log::alevel::devel, "Bad request: failed to parse uri"); - m_response.set_status(http::status_code::bad_request); - return error::make_error_code(error::invalid_uri); - } - - // extract subprotocols - lib::error_code subp_ec = m_processor->extract_subprotocols(m_request, - m_requested_subprotocols); - - if (subp_ec) { - // should we do anything? - } - - // Ask application to validate the connection - if (!m_validate_handler || m_validate_handler(m_connection_hdl)) { - m_response.set_status(http::status_code::switching_protocols); - - // Write the appropriate response headers based on request and - // processor version - ec = m_processor->process_handshake(m_request,m_subprotocol,m_response); - - if (ec) { - std::stringstream s; - s << "Processing error: " << ec << "(" << ec.message() << ")"; - m_alog->write(log::alevel::devel, s.str()); - - m_response.set_status(http::status_code::internal_server_error); - return ec; - } - } else { - // User application has rejected the handshake - m_alog->write(log::alevel::devel, "USER REJECT"); - - // Use Bad Request if the user handler did not provide a more - // specific http response error code. - // TODO: is there a better default? - if (m_response.get_status_code() == http::status_code::uninitialized) { - m_response.set_status(http::status_code::bad_request); - } - - return error::make_error_code(error::rejected); - } - - return lib::error_code(); -} - -template -void connection::write_http_response(lib::error_code const & ec) { - m_alog->write(log::alevel::devel,"connection write_http_response"); - - if (ec == error::make_error_code(error::http_connection_ended)) { - m_alog->write(log::alevel::http,"An HTTP handler took over the connection."); - return; - } - - if (m_response.get_status_code() == http::status_code::uninitialized) { - m_response.set_status(http::status_code::internal_server_error); - m_ec = error::make_error_code(error::general); - } else { - m_ec = ec; - } - - m_response.set_version("HTTP/1.1"); - - // Set server header based on the user agent settings - if (m_response.get_header("Server").empty()) { - if (!m_user_agent.empty()) { - m_response.replace_header("Server",m_user_agent); - } else { - m_response.remove_header("Server"); - } - } - - // have the processor generate the raw bytes for the wire (if it exists) - if (m_processor) { - m_handshake_buffer = m_processor->get_raw(m_response); - } else { - // a processor wont exist for raw HTTP responses. - m_handshake_buffer = m_response.raw(); - } - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer); - if (!m_response.get_header("Sec-WebSocket-Key3").empty()) { - m_alog->write(log::alevel::devel, - utility::to_hex(m_response.get_header("Sec-WebSocket-Key3"))); - } - } - - // write raw bytes - transport_con_type::async_write( - m_handshake_buffer.data(), - m_handshake_buffer.size(), - lib::bind( - &type::handle_write_http_response, - type::get_shared(), - lib::placeholders::_1 - ) - ); -} - -template -void connection::handle_write_http_response(lib::error_code const & ec) { - m_alog->write(log::alevel::devel,"handle_write_http_response"); - - lib::error_code ecm = ec; - - if (!ecm) { - scoped_lock_type lock(m_connection_state_lock); - - if (m_state == session::state::connecting) { - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - ecm = error::make_error_code(error::invalid_state); - } - } else if (m_state == session::state::closed) { - // The connection was canceled while the response was being sent, - // usually by the handshake timer. This is basically expected - // (though hopefully rare) and there is nothing we can do so ignore. - m_alog->write(log::alevel::devel, - "handle_write_http_response invoked after connection was closed"); - return; - } else { - ecm = error::make_error_code(error::invalid_state); - } - } - - if (ecm) { - if (ecm == transport::error::eof && m_state == session::state::closed) { - // we expect to get eof if the connection is closed already - m_alog->write(log::alevel::devel, - "got (expected) eof/state error from closed con"); - return; - } - - log_err(log::elevel::rerror,"handle_write_http_response",ecm); - this->terminate(ecm); - return; - } - - if (m_handshake_timer) { - m_handshake_timer->cancel(); - m_handshake_timer.reset(); - } - - if (m_response.get_status_code() != http::status_code::switching_protocols) - { - /*if (m_processor || m_ec == error::http_parse_error || - m_ec == error::invalid_version || m_ec == error::unsupported_version - || m_ec == error::upgrade_required) - {*/ - if (!m_is_http) { - std::stringstream s; - s << "Handshake ended with HTTP error: " - << m_response.get_status_code(); - m_elog->write(log::elevel::rerror,s.str()); - } else { - // if this was not a websocket connection, we have written - // the expected response and the connection can be closed. - - this->log_http_result(); - - if (m_ec) { - m_alog->write(log::alevel::devel, - "got to writing HTTP results with m_ec set: "+m_ec.message()); - } - m_ec = make_error_code(error::http_connection_ended); - } - - this->terminate(m_ec); - return; - } - - this->log_open_result(); - - m_internal_state = istate::PROCESS_CONNECTION; - m_state = session::state::open; - - if (m_open_handler) { - m_open_handler(m_connection_hdl); - } - - this->handle_read_frame(lib::error_code(), m_buf_cursor); -} - -template -void connection::send_http_request() { - m_alog->write(log::alevel::devel,"connection send_http_request"); - - // TODO: origin header? - - // Have the protocol processor fill in the appropriate fields based on the - // selected client version - if (m_processor) { - lib::error_code ec; - ec = m_processor->client_handshake_request(m_request,m_uri, - m_requested_subprotocols); - - if (ec) { - log_err(log::elevel::fatal,"Internal library error: Processor",ec); - return; - } - } else { - m_elog->write(log::elevel::fatal,"Internal library error: missing processor"); - return; - } - - // Unless the user has overridden the user agent, send generic WS++ UA. - if (m_request.get_header("User-Agent").empty()) { - if (!m_user_agent.empty()) { - m_request.replace_header("User-Agent",m_user_agent); - } else { - m_request.remove_header("User-Agent"); - } - } - - m_handshake_buffer = m_request.raw(); - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer); - } - - if (m_open_handshake_timeout_dur > 0) { - m_handshake_timer = transport_con_type::set_timer( - m_open_handshake_timeout_dur, - lib::bind( - &type::handle_open_handshake_timeout, - type::get_shared(), - lib::placeholders::_1 - ) - ); - } - - transport_con_type::async_write( - m_handshake_buffer.data(), - m_handshake_buffer.size(), - lib::bind( - &type::handle_send_http_request, - type::get_shared(), - lib::placeholders::_1 - ) - ); -} - -template -void connection::handle_send_http_request(lib::error_code const & ec) { - m_alog->write(log::alevel::devel,"handle_send_http_request"); - - lib::error_code ecm = ec; - - if (!ecm) { - scoped_lock_type lock(m_connection_state_lock); - - if (m_state == session::state::connecting) { - if (m_internal_state != istate::WRITE_HTTP_REQUEST) { - ecm = error::make_error_code(error::invalid_state); - } else { - m_internal_state = istate::READ_HTTP_RESPONSE; - } - } else if (m_state == session::state::closed) { - // The connection was canceled while the response was being sent, - // usually by the handshake timer. This is basically expected - // (though hopefully rare) and there is nothing we can do so ignore. - m_alog->write(log::alevel::devel, - "handle_send_http_request invoked after connection was closed"); - return; - } else { - ecm = error::make_error_code(error::invalid_state); - } - } - - if (ecm) { - if (ecm == transport::error::eof && m_state == session::state::closed) { - // we expect to get eof if the connection is closed already - m_alog->write(log::alevel::devel, - "got (expected) eof/state error from closed con"); - return; - } - - log_err(log::elevel::rerror,"handle_send_http_request",ecm); - this->terminate(ecm); - return; - } - - transport_con_type::async_read_at_least( - 1, - m_buf, - config::connection_read_buffer_size, - lib::bind( - &type::handle_read_http_response, - type::get_shared(), - lib::placeholders::_1, - lib::placeholders::_2 - ) - ); -} - -template -void connection::handle_read_http_response(lib::error_code const & ec, - size_t bytes_transferred) -{ - m_alog->write(log::alevel::devel,"handle_read_http_response"); - - lib::error_code ecm = ec; - - if (!ecm) { - scoped_lock_type lock(m_connection_state_lock); - - if (m_state == session::state::connecting) { - if (m_internal_state != istate::READ_HTTP_RESPONSE) { - ecm = error::make_error_code(error::invalid_state); - } - } else if (m_state == session::state::closed) { - // The connection was canceled while the response was being sent, - // usually by the handshake timer. This is basically expected - // (though hopefully rare) and there is nothing we can do so ignore. - m_alog->write(log::alevel::devel, - "handle_read_http_response invoked after connection was closed"); - return; - } else { - ecm = error::make_error_code(error::invalid_state); - } - } - - if (ecm) { - if (ecm == transport::error::eof && m_state == session::state::closed) { - // we expect to get eof if the connection is closed already - m_alog->write(log::alevel::devel, - "got (expected) eof/state error from closed con"); - return; - } - - log_err(log::elevel::rerror,"handle_read_http_response",ecm); - this->terminate(ecm); - return; - } - - size_t bytes_processed = 0; - // TODO: refactor this to use error codes rather than exceptions - try { - bytes_processed = m_response.consume(m_buf,bytes_transferred); - } catch (http::exception & e) { - m_elog->write(log::elevel::rerror, - std::string("error in handle_read_http_response: ")+e.what()); - this->terminate(make_error_code(error::general)); - return; - } - - m_alog->write(log::alevel::devel,std::string("Raw response: ")+m_response.raw()); - - if (m_response.headers_ready()) { - if (m_handshake_timer) { - m_handshake_timer->cancel(); - m_handshake_timer.reset(); - } - - lib::error_code validate_ec = m_processor->validate_server_handshake_response( - m_request, - m_response - ); - if (validate_ec) { - log_err(log::elevel::rerror,"Server handshake response",validate_ec); - this->terminate(validate_ec); - return; - } - - // Read extension parameters and set up values necessary for the end - // user to complete extension negotiation. - std::pair neg_results; - neg_results = m_processor->negotiate_extensions(m_response); - - if (neg_results.first) { - // There was a fatal error in extension negotiation. For the moment - // kill all connections that fail extension negotiation. - - // TODO: deal with cases where the response is well formed but - // doesn't match the options requested by the client. Its possible - // that the best behavior in this cases is to log and continue with - // an unextended connection. - m_alog->write(log::alevel::devel, "Extension negotiation failed: " - + neg_results.first.message()); - this->terminate(make_error_code(error::extension_neg_failed)); - // TODO: close connection with reason 1010 (and list extensions) - } - - // response is valid, connection can now be assumed to be open - m_internal_state = istate::PROCESS_CONNECTION; - m_state = session::state::open; - - this->log_open_result(); - - if (m_open_handler) { - m_open_handler(m_connection_hdl); - } - - // The remaining bytes in m_buf are frame data. Copy them to the - // beginning of the buffer and note the length. They will be read after - // the handshake completes and before more bytes are read. - std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf); - m_buf_cursor = bytes_transferred-bytes_processed; - - this->handle_read_frame(lib::error_code(), m_buf_cursor); - } else { - transport_con_type::async_read_at_least( - 1, - m_buf, - config::connection_read_buffer_size, - lib::bind( - &type::handle_read_http_response, - type::get_shared(), - lib::placeholders::_1, - lib::placeholders::_2 - ) - ); - } -} - -template -void connection::handle_open_handshake_timeout( - lib::error_code const & ec) -{ - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel,"open handshake timer cancelled"); - } else if (ec) { - m_alog->write(log::alevel::devel, - "open handle_open_handshake_timeout error: "+ec.message()); - // TODO: ignore or fail here? - } else { - m_alog->write(log::alevel::devel,"open handshake timer expired"); - terminate(make_error_code(error::open_handshake_timeout)); - } -} - -template -void connection::handle_close_handshake_timeout( - lib::error_code const & ec) -{ - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel,"asio close handshake timer cancelled"); - } else if (ec) { - m_alog->write(log::alevel::devel, - "asio open handle_close_handshake_timeout error: "+ec.message()); - // TODO: ignore or fail here? - } else { - m_alog->write(log::alevel::devel, "asio close handshake timer expired"); - terminate(make_error_code(error::close_handshake_timeout)); - } -} - -template -void connection::terminate(lib::error_code const & ec) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection terminate"); - } - - // Cancel close handshake timer - if (m_handshake_timer) { - m_handshake_timer->cancel(); - m_handshake_timer.reset(); - } - - terminate_status tstat = unknown; - if (ec) { - m_ec = ec; - m_local_close_code = close::status::abnormal_close; - m_local_close_reason = ec.message(); - } - - // TODO: does any of this need a mutex? - if (m_is_http) { - m_http_state = session::http_state::closed; - } - if (m_state == session::state::connecting) { - m_state = session::state::closed; - tstat = failed; - - // Log fail result here before socket is shut down and we can't get - // the remote address, etc anymore - if (m_ec != error::http_connection_ended) { - log_fail_result(); - } - } else if (m_state != session::state::closed) { - m_state = session::state::closed; - tstat = closed; - } else { - m_alog->write(log::alevel::devel, - "terminate called on connection that was already terminated"); - return; - } - - // TODO: choose between shutdown and close based on error code sent - - transport_con_type::async_shutdown( - lib::bind( - &type::handle_terminate, - type::get_shared(), - tstat, - lib::placeholders::_1 - ) - ); -} - -template -void connection::handle_terminate(terminate_status tstat, - lib::error_code const & ec) -{ - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection handle_terminate"); - } - - if (ec) { - // there was an error actually shutting down the connection - log_err(log::elevel::devel,"handle_terminate",ec); - } - - // clean shutdown - if (tstat == failed) { - if (m_ec != error::http_connection_ended) { - if (m_fail_handler) { - m_fail_handler(m_connection_hdl); - } - } - } else if (tstat == closed) { - if (m_close_handler) { - m_close_handler(m_connection_hdl); - } - log_close_result(); - } else { - m_elog->write(log::elevel::rerror,"Unknown terminate_status"); - } - - // call the termination handler if it exists - // if it exists it might (but shouldn't) refer to a bad memory location. - // If it does, we don't care and should catch and ignore it. - if (m_termination_handler) { - try { - m_termination_handler(type::get_shared()); - } catch (std::exception const & e) { - m_elog->write(log::elevel::warn, - std::string("termination_handler call failed. Reason was: ")+e.what()); - } - } -} - -template -void connection::write_frame() { - //m_alog->write(log::alevel::devel,"connection write_frame"); - - { - scoped_lock_type lock(m_write_lock); - - // Check the write flag. If true, there is an outstanding transport - // write already. In this case we just return. The write handler will - // start a new write if the write queue isn't empty. If false, we set - // the write flag and proceed to initiate a transport write. - if (m_write_flag) { - return; - } - - // pull off all the messages that are ready to write. - // stop if we get a message marked terminal - message_ptr next_message = write_pop(); - while (next_message) { - m_current_msgs.push_back(next_message); - if (!next_message->get_terminal()) { - next_message = write_pop(); - } else { - next_message = message_ptr(); - } - } - - if (m_current_msgs.empty()) { - // there was nothing to send - return; - } else { - // At this point we own the next messages to be sent and are - // responsible for holding the write flag until they are - // successfully sent or there is some error - m_write_flag = true; - } - } - - typename std::vector::iterator it; - for (it = m_current_msgs.begin(); it != m_current_msgs.end(); ++it) { - std::string const & header = (*it)->get_header(); - std::string const & payload = (*it)->get_payload(); - - m_send_buffer.push_back(transport::buffer(header.c_str(),header.size())); - m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size())); - } - - // Print detailed send stats if those log levels are enabled - if (m_alog->static_test(log::alevel::frame_header)) { - if (m_alog->dynamic_test(log::alevel::frame_header)) { - std::stringstream general,header,payload; - - general << "Dispatching write containing " << m_current_msgs.size() - <<" message(s) containing "; - header << "Header Bytes: \n"; - payload << "Payload Bytes: \n"; - - size_t hbytes = 0; - size_t pbytes = 0; - - for (size_t i = 0; i < m_current_msgs.size(); i++) { - hbytes += m_current_msgs[i]->get_header().size(); - pbytes += m_current_msgs[i]->get_payload().size(); - - - header << "[" << i << "] (" - << m_current_msgs[i]->get_header().size() << ") " - << utility::to_hex(m_current_msgs[i]->get_header()) << "\n"; - - if (m_alog->static_test(log::alevel::frame_payload)) { - if (m_alog->dynamic_test(log::alevel::frame_payload)) { - payload << "[" << i << "] (" - << m_current_msgs[i]->get_payload().size() << ") ["<get_opcode()<<"] " - << (m_current_msgs[i]->get_opcode() == frame::opcode::text ? - m_current_msgs[i]->get_payload() : - utility::to_hex(m_current_msgs[i]->get_payload()) - ) - << "\n"; - } - } - } - - general << hbytes << " header bytes and " << pbytes << " payload bytes"; - - m_alog->write(log::alevel::frame_header,general.str()); - m_alog->write(log::alevel::frame_header,header.str()); - m_alog->write(log::alevel::frame_payload,payload.str()); - } - } - - transport_con_type::async_write( - m_send_buffer, - m_write_frame_handler - ); -} - -template -void connection::handle_write_frame(lib::error_code const & ec) -{ - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"connection handle_write_frame"); - } - - bool terminal = m_current_msgs.back()->get_terminal(); - - m_send_buffer.clear(); - m_current_msgs.clear(); - // TODO: recycle instead of deleting - - if (ec) { - log_err(log::elevel::fatal,"handle_write_frame",ec); - this->terminate(ec); - return; - } - - if (terminal) { - this->terminate(lib::error_code()); - return; - } - - bool needs_writing = false; - { - scoped_lock_type lock(m_write_lock); - - // release write flag - m_write_flag = false; - - needs_writing = !m_send_queue.empty(); - } - - if (needs_writing) { - transport_con_type::dispatch(lib::bind( - &type::write_frame, - type::get_shared() - )); - } -} - -template -std::vector const & connection::get_supported_versions() const -{ - return versions_supported; -} - -template -void connection::process_control_frame(typename config::message_type::ptr msg) -{ - m_alog->write(log::alevel::devel,"process_control_frame"); - - frame::opcode::value op = msg->get_opcode(); - lib::error_code ec; - - std::stringstream s; - s << "Control frame received with opcode " << op; - m_alog->write(log::alevel::control,s.str()); - - if (m_state == session::state::closed) { - m_elog->write(log::elevel::warn,"got frame in state closed"); - return; - } - if (op != frame::opcode::CLOSE && m_state != session::state::open) { - m_elog->write(log::elevel::warn,"got non-close frame in state closing"); - return; - } - - if (op == frame::opcode::PING) { - bool should_reply = true; - - if (m_ping_handler) { - should_reply = m_ping_handler(m_connection_hdl, msg->get_payload()); - } - - if (should_reply) { - this->pong(msg->get_payload(),ec); - if (ec) { - log_err(log::elevel::devel,"Failed to send response pong",ec); - } - } - } else if (op == frame::opcode::PONG) { - if (m_pong_handler) { - m_pong_handler(m_connection_hdl, msg->get_payload()); - } - if (m_ping_timer) { - m_ping_timer->cancel(); - } - } else if (op == frame::opcode::CLOSE) { - m_alog->write(log::alevel::devel,"got close frame"); - // record close code and reason somewhere - - m_remote_close_code = close::extract_code(msg->get_payload(),ec); - if (ec) { - s.str(""); - if (config::drop_on_protocol_error) { - s << "Received invalid close code " << m_remote_close_code - << " dropping connection per config."; - m_elog->write(log::elevel::devel,s.str()); - this->terminate(ec); - } else { - s << "Received invalid close code " << m_remote_close_code - << " sending acknowledgement and closing"; - m_elog->write(log::elevel::devel,s.str()); - ec = send_close_ack(close::status::protocol_error, - "Invalid close code"); - if (ec) { - log_err(log::elevel::devel,"send_close_ack",ec); - } - } - return; - } - - m_remote_close_reason = close::extract_reason(msg->get_payload(),ec); - if (ec) { - if (config::drop_on_protocol_error) { - m_elog->write(log::elevel::devel, - "Received invalid close reason. Dropping connection per config"); - this->terminate(ec); - } else { - m_elog->write(log::elevel::devel, - "Received invalid close reason. Sending acknowledgement and closing"); - ec = send_close_ack(close::status::protocol_error, - "Invalid close reason"); - if (ec) { - log_err(log::elevel::devel,"send_close_ack",ec); - } - } - return; - } - - if (m_state == session::state::open) { - s.str(""); - s << "Received close frame with code " << m_remote_close_code - << " and reason " << m_remote_close_reason; - m_alog->write(log::alevel::devel,s.str()); - - ec = send_close_ack(); - if (ec) { - log_err(log::elevel::devel,"send_close_ack",ec); - } - } else if (m_state == session::state::closing && !m_was_clean) { - // ack of our close - m_alog->write(log::alevel::devel, "Got acknowledgement of close"); - - m_was_clean = true; - - // If we are a server terminate the connection now. Clients should - // leave the connection open to give the server an opportunity to - // initiate the TCP close. The client's timer will handle closing - // its side of the connection if the server misbehaves. - // - // TODO: different behavior if the underlying transport doesn't - // support timers? - if (m_is_server) { - terminate(lib::error_code()); - } - } else { - // spurious, ignore - m_elog->write(log::elevel::devel, "Got close frame in wrong state"); - } - } else { - // got an invalid control opcode - m_elog->write(log::elevel::devel, "Got control frame with invalid opcode"); - // initiate protocol error shutdown - } -} - -template -lib::error_code connection::send_close_ack(close::status::value code, - std::string const & reason) -{ - return send_close_frame(code,reason,true,m_is_server); -} - -template -lib::error_code connection::send_close_frame(close::status::value code, - std::string const & reason, bool ack, bool terminal) -{ - m_alog->write(log::alevel::devel,"send_close_frame"); - - // check for special codes - - // If silent close is set, respect it and blank out close information - // Otherwise use whatever has been specified in the parameters. If - // parameters specifies close::status::blank then determine what to do - // based on whether or not this is an ack. If it is not an ack just - // send blank info. If it is an ack then echo the close information from - // the remote endpoint. - if (config::silent_close) { - m_alog->write(log::alevel::devel,"closing silently"); - m_local_close_code = close::status::no_status; - m_local_close_reason.clear(); - } else if (code != close::status::blank) { - m_alog->write(log::alevel::devel,"closing with specified codes"); - m_local_close_code = code; - m_local_close_reason = reason; - } else if (!ack) { - m_alog->write(log::alevel::devel,"closing with no status code"); - m_local_close_code = close::status::no_status; - m_local_close_reason.clear(); - } else if (m_remote_close_code == close::status::no_status) { - m_alog->write(log::alevel::devel, - "acknowledging a no-status close with normal code"); - m_local_close_code = close::status::normal; - m_local_close_reason.clear(); - } else { - m_alog->write(log::alevel::devel,"acknowledging with remote codes"); - m_local_close_code = m_remote_close_code; - m_local_close_reason = m_remote_close_reason; - } - - std::stringstream s; - s << "Closing with code: " << m_local_close_code << ", and reason: " - << m_local_close_reason; - m_alog->write(log::alevel::devel,s.str()); - - message_ptr msg = m_msg_manager->get_message(); - if (!msg) { - return error::make_error_code(error::no_outgoing_buffers); - } - - lib::error_code ec = m_processor->prepare_close(m_local_close_code, - m_local_close_reason,msg); - if (ec) { - return ec; - } - - // Messages flagged terminal will result in the TCP connection being dropped - // after the message has been written. This is typically used when servers - // send an ack and when any endpoint encounters a protocol error - if (terminal) { - msg->set_terminal(true); - } - - m_state = session::state::closing; - - if (ack) { - m_was_clean = true; - } - - // Start a timer so we don't wait forever for the acknowledgement close - // frame - if (m_close_handshake_timeout_dur > 0) { - m_handshake_timer = transport_con_type::set_timer( - m_close_handshake_timeout_dur, - lib::bind( - &type::handle_close_handshake_timeout, - type::get_shared(), - lib::placeholders::_1 - ) - ); - } - - bool needs_writing = false; - { - scoped_lock_type lock(m_write_lock); - write_push(msg); - needs_writing = !m_write_flag && !m_send_queue.empty(); - } - - if (needs_writing) { - transport_con_type::dispatch(lib::bind( - &type::write_frame, - type::get_shared() - )); - } - - return lib::error_code(); -} - -template -typename connection::processor_ptr -connection::get_processor(int version) const { - // TODO: allow disabling certain versions - - processor_ptr p; - - switch (version) { - case 0: - p = lib::make_shared >( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager - ); - break; - case 7: - p = lib::make_shared >( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - lib::ref(m_rng) - ); - break; - case 8: - p = lib::make_shared >( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - lib::ref(m_rng) - ); - break; - case 13: - p = lib::make_shared >( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - lib::ref(m_rng) - ); - break; - default: - return p; - } - - // Settings not configured by the constructor - p->set_max_message_size(m_max_message_size); - - return p; -} - -template -void connection::write_push(typename config::message_type::ptr msg) -{ - if (!msg) { - return; - } - - m_send_buffer_size += msg->get_payload().size(); - m_send_queue.push(msg); - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "write_push: message count: " << m_send_queue.size() - << " buffer size: " << m_send_buffer_size; - m_alog->write(log::alevel::devel,s.str()); - } -} - -template -typename config::message_type::ptr connection::write_pop() -{ - message_ptr msg; - - if (m_send_queue.empty()) { - return msg; - } - - msg = m_send_queue.front(); - - m_send_buffer_size -= msg->get_payload().size(); - m_send_queue.pop(); - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "write_pop: message count: " << m_send_queue.size() - << " buffer size: " << m_send_buffer_size; - m_alog->write(log::alevel::devel,s.str()); - } - return msg; -} - -template -void connection::log_open_result() -{ - std::stringstream s; - - int version; - if (!processor::is_websocket_handshake(m_request)) { - version = -1; - } else { - version = processor::get_websocket_version(m_request); - } - - // Connection Type - s << (version == -1 ? "HTTP" : "WebSocket") << " Connection "; - - // Remote endpoint address - s << transport_con_type::get_remote_endpoint() << " "; - - // Version string if WebSocket - if (version != -1) { - s << "v" << version << " "; - } - - // User Agent - std::string ua = m_request.get_header("User-Agent"); - if (ua.empty()) { - s << "\"\" "; - } else { - // check if there are any quotes in the user agent - s << "\"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; - } - - // URI - s << (m_uri ? m_uri->get_resource() : "NULL") << " "; - - // Status code - s << m_response.get_status_code(); - - m_alog->write(log::alevel::connect,s.str()); -} - -template -void connection::log_close_result() -{ - std::stringstream s; - - s << "Disconnect " - << "close local:[" << m_local_close_code - << (m_local_close_reason.empty() ? "" : ","+m_local_close_reason) - << "] remote:[" << m_remote_close_code - << (m_remote_close_reason.empty() ? "" : ","+m_remote_close_reason) << "]"; - - m_alog->write(log::alevel::disconnect,s.str()); -} - -template -void connection::log_fail_result() -{ - std::stringstream s; - - int version = processor::get_websocket_version(m_request); - - // Connection Type - s << "WebSocket Connection "; - - // Remote endpoint address & WebSocket version - s << transport_con_type::get_remote_endpoint(); - if (version < 0) { - s << " -"; - } else { - s << " v" << version; - } - - // User Agent - std::string ua = m_request.get_header("User-Agent"); - if (ua.empty()) { - s << " \"\" "; - } else { - // check if there are any quotes in the user agent - s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; - } - - // URI - s << (m_uri ? m_uri->get_resource() : "-"); - - // HTTP Status code - s << " " << m_response.get_status_code(); - - // WebSocket++ error code & reason - s << " " << m_ec << " " << m_ec.message(); - - m_alog->write(log::alevel::fail,s.str()); -} - -template -void connection::log_http_result() { - std::stringstream s; - - if (processor::is_websocket_handshake(m_request)) { - m_alog->write(log::alevel::devel,"Call to log_http_result for WebSocket"); - return; - } - - // Connection Type - s << (m_request.get_header("host").empty() ? "-" : m_request.get_header("host")) - << " " << transport_con_type::get_remote_endpoint() - << " \"" << m_request.get_method() - << " " << (m_uri ? m_uri->get_resource() : "-") - << " " << m_request.get_version() << "\" " << m_response.get_status_code() - << " " << m_response.get_body().size(); - - // User Agent - std::string ua = m_request.get_header("User-Agent"); - if (ua.empty()) { - s << " \"\" "; - } else { - // check if there are any quotes in the user agent - s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; - } - - m_alog->write(log::alevel::http,s.str()); -} - -} // namespace websocketpp - -#endif // WEBSOCKETPP_CONNECTION_IMPL_HPP +/* + * 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_IMPL_HPP +#define WEBSOCKETPP_CONNECTION_IMPL_HPP + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace websocketpp { + +namespace istate = session::internal_state; + +template +void connection::set_termination_handler( + termination_handler new_handler) +{ + m_alog->write(log::alevel::devel, + "connection set_termination_handler"); + + //scoped_lock_type lock(m_connection_state_lock); + + m_termination_handler = new_handler; +} + +template +std::string const & connection::get_origin() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_processor->get_origin(m_request); +} + +template +size_t connection::get_buffered_amount() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_send_buffer_size; +} + +template +session::state::value connection::get_state() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_state; +} + +template +lib::error_code connection::send(std::string const & payload, + frame::opcode::value op) +{ + message_ptr msg = m_msg_manager->get_message(op,payload.size()); + msg->append_payload(payload); + msg->set_compressed(true); + + return send(msg); +} + +template +lib::error_code connection::send(void const * payload, size_t len, + frame::opcode::value op) +{ + message_ptr msg = m_msg_manager->get_message(op,len); + msg->append_payload(payload,len); + + return send(msg); +} + +template +lib::error_code connection::send(typename config::message_type::ptr msg) +{ + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection send"); + } + + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + return error::make_error_code(error::invalid_state); + } + } + + message_ptr outgoing_msg; + bool needs_writing = false; + + if (msg->get_prepared()) { + outgoing_msg = msg; + + scoped_lock_type lock(m_write_lock); + write_push(outgoing_msg); + needs_writing = !m_write_flag && !m_send_queue.empty(); + } else { + outgoing_msg = m_msg_manager->get_message(); + + if (!outgoing_msg) { + return error::make_error_code(error::no_outgoing_buffers); + } + + scoped_lock_type lock(m_write_lock); + lib::error_code ec = m_processor->prepare_data_frame(msg,outgoing_msg); + + if (ec) { + return ec; + } + + write_push(outgoing_msg); + needs_writing = !m_write_flag && !m_send_queue.empty(); + } + + if (needs_writing) { + transport_con_type::dispatch(lib::bind( + &type::write_frame, + type::get_shared() + )); + } + + return lib::error_code(); +} + +template +void connection::ping(std::string const& payload, lib::error_code& ec) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection ping"); + } + + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + std::stringstream ss; + ss << "connection::ping called from invalid state " << m_state; + m_alog->write(log::alevel::devel,ss.str()); + ec = error::make_error_code(error::invalid_state); + return; + } + } + + message_ptr msg = m_msg_manager->get_message(); + if (!msg) { + ec = error::make_error_code(error::no_outgoing_buffers); + return; + } + + ec = m_processor->prepare_ping(payload,msg); + if (ec) {return;} + + // set ping timer if we are listening for one + if (m_pong_timeout_handler) { + // Cancel any existing timers + if (m_ping_timer) { + m_ping_timer->cancel(); + } + + if (m_pong_timeout_dur > 0) { + m_ping_timer = transport_con_type::set_timer( + m_pong_timeout_dur, + lib::bind( + &type::handle_pong_timeout, + type::get_shared(), + payload, + lib::placeholders::_1 + ) + ); + } + + if (!m_ping_timer) { + // Our transport doesn't support timers + m_elog->write(log::elevel::warn,"Warning: a pong_timeout_handler is \ + set but the transport in use does not support timeouts."); + } + } + + bool needs_writing = false; + { + scoped_lock_type lock(m_write_lock); + write_push(msg); + needs_writing = !m_write_flag && !m_send_queue.empty(); + } + + if (needs_writing) { + transport_con_type::dispatch(lib::bind( + &type::write_frame, + type::get_shared() + )); + } + + ec = lib::error_code(); +} + +template +void connection::ping(std::string const & payload) { + lib::error_code ec; + ping(payload,ec); + if (ec) { + throw exception(ec); + } +} + +template +void connection::handle_pong_timeout(std::string payload, + lib::error_code const & ec) +{ + if (ec) { + if (ec == transport::error::operation_aborted) { + // ignore, this is expected + return; + } + + m_elog->write(log::elevel::devel,"pong_timeout error: "+ec.message()); + return; + } + + if (m_pong_timeout_handler) { + m_pong_timeout_handler(m_connection_hdl,payload); + } +} + +template +void connection::pong(std::string const& payload, lib::error_code& ec) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection pong"); + } + + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + std::stringstream ss; + ss << "connection::pong called from invalid state " << m_state; + m_alog->write(log::alevel::devel,ss.str()); + ec = error::make_error_code(error::invalid_state); + return; + } + } + + message_ptr msg = m_msg_manager->get_message(); + if (!msg) { + ec = error::make_error_code(error::no_outgoing_buffers); + return; + } + + ec = m_processor->prepare_pong(payload,msg); + if (ec) {return;} + + bool needs_writing = false; + { + scoped_lock_type lock(m_write_lock); + write_push(msg); + needs_writing = !m_write_flag && !m_send_queue.empty(); + } + + if (needs_writing) { + transport_con_type::dispatch(lib::bind( + &type::write_frame, + type::get_shared() + )); + } + + ec = lib::error_code(); +} + +template +void connection::pong(std::string const & payload) { + lib::error_code ec; + pong(payload,ec); + if (ec) { + throw exception(ec); + } +} + +template +void connection::close(close::status::value const code, + std::string const & reason, lib::error_code & ec) +{ + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection close"); + } + + // Truncate reason to maximum size allowable in a close frame. + std::string tr(reason,0,std::min(reason.size(), + frame::limits::close_reason_size)); + + scoped_lock_type lock(m_connection_state_lock); + + if (m_state != session::state::open) { + ec = error::make_error_code(error::invalid_state); + return; + } + + ec = this->send_close_frame(code,tr,false,close::status::terminal(code)); +} + +template +void connection::close(close::status::value const code, + std::string const & reason) +{ + lib::error_code ec; + close(code,reason,ec); + if (ec) { + throw exception(ec); + } +} + +/// Trigger the on_interrupt handler +/** + * This is thread safe if the transport is thread safe + */ +template +lib::error_code connection::interrupt() { + m_alog->write(log::alevel::devel,"connection connection::interrupt"); + return transport_con_type::interrupt( + lib::bind( + &type::handle_interrupt, + type::get_shared() + ) + ); +} + + +template +void connection::handle_interrupt() { + if (m_interrupt_handler) { + m_interrupt_handler(m_connection_hdl); + } +} + +template +lib::error_code connection::pause_reading() { + m_alog->write(log::alevel::devel,"connection connection::pause_reading"); + return transport_con_type::dispatch( + lib::bind( + &type::handle_pause_reading, + type::get_shared() + ) + ); +} + +/// Pause reading handler. Not safe to call directly +template +void connection::handle_pause_reading() { + m_alog->write(log::alevel::devel,"connection connection::handle_pause_reading"); + m_read_flag = false; +} + +template +lib::error_code connection::resume_reading() { + m_alog->write(log::alevel::devel,"connection connection::resume_reading"); + return transport_con_type::dispatch( + lib::bind( + &type::handle_resume_reading, + type::get_shared() + ) + ); +} + +/// Resume reading helper method. Not safe to call directly +template +void connection::handle_resume_reading() { + m_read_flag = true; + read_frame(); +} + + + + + + + + + + + +template +bool connection::get_secure() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_uri->get_secure(); +} + +template +std::string const & connection::get_host() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_uri->get_host(); +} + +template +std::string const & connection::get_resource() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_uri->get_resource(); +} + +template +uint16_t connection::get_port() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_uri->get_port(); +} + +template +uri_ptr connection::get_uri() const { + //scoped_lock_type lock(m_connection_state_lock); + return m_uri; +} + +template +void connection::set_uri(uri_ptr uri) { + //scoped_lock_type lock(m_connection_state_lock); + m_uri = uri; +} + + + + + + +template +std::string const & connection::get_subprotocol() const { + return m_subprotocol; +} + +template +std::vector const & +connection::get_requested_subprotocols() const { + return m_requested_subprotocols; +} + +template +void connection::add_subprotocol(std::string const & value, + lib::error_code & ec) +{ + if (m_is_server) { + ec = error::make_error_code(error::client_only); + return; + } + + // If the value is empty or has a non-RFC2616 token character it is invalid. + if (value.empty() || std::find_if(value.begin(),value.end(), + http::is_not_token_char) != value.end()) + { + ec = error::make_error_code(error::invalid_subprotocol); + return; + } + + m_requested_subprotocols.push_back(value); +} + +template +void connection::add_subprotocol(std::string const & value) { + lib::error_code ec; + this->add_subprotocol(value,ec); + if (ec) { + throw exception(ec); + } +} + + +template +void connection::select_subprotocol(std::string const & value, + lib::error_code & ec) +{ + if (!m_is_server) { + ec = error::make_error_code(error::server_only); + return; + } + + if (value.empty()) { + ec = lib::error_code(); + return; + } + + std::vector::iterator it; + + it = std::find(m_requested_subprotocols.begin(), + m_requested_subprotocols.end(), + value); + + if (it == m_requested_subprotocols.end()) { + ec = error::make_error_code(error::unrequested_subprotocol); + return; + } + + m_subprotocol = value; +} + +template +void connection::select_subprotocol(std::string const & value) { + lib::error_code ec; + this->select_subprotocol(value,ec); + if (ec) { + throw exception(ec); + } +} + + +template +std::string const & +connection::get_request_header(std::string const & key) const { + return m_request.get_header(key); +} + +template +std::string const & +connection::get_request_body() const { + return m_request.get_body(); +} + +template +std::string const & +connection::get_response_header(std::string const & key) const { + return m_response.get_header(key); +} + +// TODO: EXCEPTION_FREE +template +void connection::set_status(http::status_code::value code) +{ + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); + } + m_response.set_status(code); +} + +// TODO: EXCEPTION_FREE +template +void connection::set_status(http::status_code::value code, + std::string const & msg) +{ + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); + } + + m_response.set_status(code,msg); +} + +// TODO: EXCEPTION_FREE +template +void connection::set_body(std::string const & value) { + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); + } + + m_response.set_body(value); +} + +// TODO: EXCEPTION_FREE +template +void connection::append_header(std::string const & key, + std::string const & val) +{ + if (m_is_server) { + if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { + // we are setting response headers for an incoming server connection + m_response.append_header(key,val); + } else { + throw exception("Call to append_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } else { + if (m_internal_state == istate::USER_INIT) { + // we are setting initial headers for an outgoing client connection + m_request.append_header(key,val); + } else { + throw exception("Call to append_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } +} + +// TODO: EXCEPTION_FREE +template +void connection::replace_header(std::string const & key, + std::string const & val) +{ + if (m_is_server) { + if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { + // we are setting response headers for an incoming server connection + m_response.replace_header(key,val); + } else { + throw exception("Call to replace_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } else { + if (m_internal_state == istate::USER_INIT) { + // we are setting initial headers for an outgoing client connection + m_request.replace_header(key,val); + } else { + throw exception("Call to replace_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } +} + +// TODO: EXCEPTION_FREE +template +void connection::remove_header(std::string const & key) +{ + if (m_is_server) { + if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { + // we are setting response headers for an incoming server connection + m_response.remove_header(key); + } else { + throw exception("Call to remove_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } else { + if (m_internal_state == istate::USER_INIT) { + // we are setting initial headers for an outgoing client connection + m_request.remove_header(key); + } else { + throw exception("Call to remove_header from invalid state", + error::make_error_code(error::invalid_state)); + } + } +} + +/// Defer HTTP Response until later +/** + * Used in the http handler to defer the HTTP response for this connection + * until later. Handshake timers will be canceled and the connection will be + * left open until `send_http_response` or an equivalent is called. + * + * Warning: deferred connections won't time out and as a result can tie up + * resources. + * + * @return A status code, zero on success, non-zero otherwise + */ +template +lib::error_code connection::defer_http_response() { + // Cancel handshake timer, otherwise the connection will time out and we'll + // close the connection before the app has a chance to send a response. + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + + // Do something to signal deferral + m_http_state = session::http_state::deferred; + + return lib::error_code(); +} + +/// 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. + * + * @since 0.6.0 + * + * @param ec A status code, zero on success, non-zero otherwise + */ +template +void connection::send_http_response(lib::error_code & ec) { + { + scoped_lock_type lock(m_connection_state_lock); + if (m_http_state != session::http_state::deferred) { + ec = error::make_error_code(error::invalid_state); + return; + } + + m_http_state = session::http_state::body_written; + } + + this->write_http_response(lib::error_code()); + ec = lib::error_code(); +} + +template +void connection::send_http_response() { + lib::error_code ec; + this->send_http_response(ec); + if (ec) { + throw exception(ec); + } +} + + + + +/******** logic thread ********/ + +template +void connection::start() { + m_alog->write(log::alevel::devel,"connection start"); + + if (m_internal_state != istate::USER_INIT) { + m_alog->write(log::alevel::devel,"Start called in invalid state"); + this->terminate(error::make_error_code(error::invalid_state)); + return; + } + + m_internal_state = istate::TRANSPORT_INIT; + + // Depending on how the transport implements init this function may return + // immediately and call handle_transport_init later or call + // handle_transport_init from this function. + transport_con_type::init( + lib::bind( + &type::handle_transport_init, + type::get_shared(), + lib::placeholders::_1 + ) + ); +} + +template +void connection::handle_transport_init(lib::error_code const & ec) { + m_alog->write(log::alevel::devel,"connection handle_transport_init"); + + lib::error_code ecm = ec; + + if (m_internal_state != istate::TRANSPORT_INIT) { + m_alog->write(log::alevel::devel, + "handle_transport_init must be called from transport init state"); + ecm = error::make_error_code(error::invalid_state); + } + + if (ecm) { + std::stringstream s; + s << "handle_transport_init received error: "<< ecm.message(); + m_elog->write(log::elevel::rerror,s.str()); + + this->terminate(ecm); + return; + } + + // At this point the transport is ready to read and write bytes. + if (m_is_server) { + m_internal_state = istate::READ_HTTP_REQUEST; + this->read_handshake(1); + } else { + // We are a client. Set the processor to the version specified in the + // config file and send a handshake request. + m_internal_state = istate::WRITE_HTTP_REQUEST; + m_processor = get_processor(config::client_version); + this->send_http_request(); + } +} + +template +void connection::read_handshake(size_t num_bytes) { + m_alog->write(log::alevel::devel,"connection read_handshake"); + + if (m_open_handshake_timeout_dur > 0) { + m_handshake_timer = transport_con_type::set_timer( + m_open_handshake_timeout_dur, + lib::bind( + &type::handle_open_handshake_timeout, + type::get_shared(), + lib::placeholders::_1 + ) + ); + } + + transport_con_type::async_read_at_least( + num_bytes, + m_buf, + config::connection_read_buffer_size, + lib::bind( + &type::handle_read_handshake, + type::get_shared(), + lib::placeholders::_1, + lib::placeholders::_2 + ) + ); +} + +// All exit paths for this function need to call write_http_response() or submit +// a new read request with this function as the handler. +template +void connection::handle_read_handshake(lib::error_code const & ec, + size_t bytes_transferred) +{ + m_alog->write(log::alevel::devel,"connection handle_read_handshake"); + + lib::error_code ecm = ec; + + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::READ_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog->write(log::alevel::devel, + "handle_read_handshake invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } + } + + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog->write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_read_handshake",ecm); + this->terminate(ecm); + return; + } + + // Boundaries checking. TODO: How much of this should be done? + if (bytes_transferred > config::connection_read_buffer_size) { + m_elog->write(log::elevel::fatal,"Fatal boundaries checking error."); + this->terminate(make_error_code(error::general)); + return; + } + + size_t bytes_processed = 0; + try { + bytes_processed = m_request.consume(m_buf,bytes_transferred); + } catch (http::exception &e) { + // All HTTP exceptions will result in this request failing and an error + // response being returned. No more bytes will be read in this con. + m_response.set_status(e.m_error_code,e.m_error_msg); + this->write_http_response_error(error::make_error_code(error::http_parse_error)); + return; + } + + // More paranoid boundaries checking. + // TODO: Is this overkill? + if (bytes_processed > bytes_transferred) { + m_elog->write(log::elevel::fatal,"Fatal boundaries checking error."); + this->terminate(make_error_code(error::general)); + return; + } + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "bytes_transferred: " << bytes_transferred + << " bytes, bytes processed: " << bytes_processed << " bytes"; + m_alog->write(log::alevel::devel,s.str()); + } + + if (m_request.ready()) { + lib::error_code processor_ec = this->initialize_processor(); + if (processor_ec) { + this->write_http_response_error(processor_ec); + return; + } + + if (m_processor && m_processor->get_version() == 0) { + // Version 00 has an extra requirement to read some bytes after the + // handshake + if (bytes_transferred-bytes_processed >= 8) { + m_request.replace_header( + "Sec-WebSocket-Key3", + std::string(m_buf+bytes_processed,m_buf+bytes_processed+8) + ); + bytes_processed += 8; + } else { + // TODO: need more bytes + m_alog->write(log::alevel::devel,"short key3 read"); + m_response.set_status(http::status_code::internal_server_error); + this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3)); + return; + } + } + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,m_request.raw()); + if (!m_request.get_header("Sec-WebSocket-Key3").empty()) { + m_alog->write(log::alevel::devel, + utility::to_hex(m_request.get_header("Sec-WebSocket-Key3"))); + } + } + + // The remaining bytes in m_buf are frame data. Copy them to the + // beginning of the buffer and note the length. They will be read after + // the handshake completes and before more bytes are read. + std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf); + m_buf_cursor = bytes_transferred-bytes_processed; + + + m_internal_state = istate::PROCESS_HTTP_REQUEST; + + // We have the complete request. Process it. + lib::error_code handshake_ec = this->process_handshake_request(); + + // Write a response if this is a websocket connection or if it is an + // HTTP connection for which the response has not been deferred or + // started yet by a different system (i.e. still in init state). + if (!m_is_http || m_http_state == session::http_state::init) { + this->write_http_response(handshake_ec); + } + } else { + // read at least 1 more byte + transport_con_type::async_read_at_least( + 1, + m_buf, + config::connection_read_buffer_size, + lib::bind( + &type::handle_read_handshake, + type::get_shared(), + lib::placeholders::_1, + lib::placeholders::_2 + ) + ); + } +} + +// write_http_response requires the request to be fully read and the connection +// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors +// before the request is fully read (specifically at a point where we aren't +// sure if the hybi00 key3 bytes need to be read). This method sets the correct +// state and calls write_http_response +template +void connection::write_http_response_error(lib::error_code const & ec) { + if (m_internal_state != istate::READ_HTTP_REQUEST) { + m_alog->write(log::alevel::devel, + "write_http_response_error called in invalid state"); + this->terminate(error::make_error_code(error::invalid_state)); + return; + } + + m_internal_state = istate::PROCESS_HTTP_REQUEST; + + this->write_http_response(ec); +} + +// All exit paths for this function need to call write_http_response() or submit +// a new read request with this function as the handler. +template +void connection::handle_read_frame(lib::error_code const & ec, + size_t bytes_transferred) +{ + //m_alog->write(log::alevel::devel,"connection handle_read_frame"); + + lib::error_code ecm = ec; + + if (!ecm && m_internal_state != istate::PROCESS_CONNECTION) { + ecm = error::make_error_code(error::invalid_state); + } + + if (ecm) { + log::level echannel = log::elevel::rerror; + + if (ecm == transport::error::eof) { + if (m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + // just ignore it + m_alog->write(log::alevel::devel,"got eof from closed con"); + return; + } else if (m_state == session::state::closing && !m_is_server) { + // If we are a client we expect to get eof in the closing state, + // this is a signal to terminate our end of the connection after + // the closing handshake + terminate(lib::error_code()); + return; + } + } else if (ecm == error::invalid_state) { + // In general, invalid state errors in the closed state are the + // result of handlers that were in the system already when the state + // changed and should be ignored as they pose no problems and there + // is nothing useful that we can do about them. + if (m_state == session::state::closed) { + m_alog->write(log::alevel::devel, + "handle_read_frame: got invalid istate in closed state"); + return; + } + } else if (ecm == transport::error::action_after_shutdown) { + echannel = log::elevel::info; + } else { + // TODO: more generally should we do something different here in the + // case that m_state is cosed? Are errors after the connection is + // already closed really an rerror? + } + + + + log_err(echannel, "handle_read_frame", ecm); + this->terminate(ecm); + return; + } + + // Boundaries checking. TODO: How much of this should be done? + /*if (bytes_transferred > config::connection_read_buffer_size) { + m_elog->write(log::elevel::fatal,"Fatal boundaries checking error"); + this->terminate(make_error_code(error::general)); + return; + }*/ + + size_t p = 0; + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "p = " << p << " bytes transferred = " << bytes_transferred; + m_alog->write(log::alevel::devel,s.str()); + } + + while (p < bytes_transferred) { + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "calling consume with " << bytes_transferred-p << " bytes"; + m_alog->write(log::alevel::devel,s.str()); + } + + lib::error_code consume_ec; + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "Processing Bytes: " << utility::to_hex(reinterpret_cast(m_buf)+p,bytes_transferred-p); + m_alog->write(log::alevel::devel,s.str()); + } + + p += m_processor->consume( + reinterpret_cast(m_buf)+p, + bytes_transferred-p, + consume_ec + ); + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "bytes left after consume: " << bytes_transferred-p; + m_alog->write(log::alevel::devel,s.str()); + } + if (consume_ec) { + log_err(log::elevel::rerror, "consume", consume_ec); + + if (config::drop_on_protocol_error) { + this->terminate(consume_ec); + return; + } else { + lib::error_code close_ec; + this->close( + processor::error::to_ws(consume_ec), + consume_ec.message(), + close_ec + ); + + if (close_ec) { + log_err(log::elevel::fatal, "Protocol error close frame ", close_ec); + this->terminate(close_ec); + return; + } + } + return; + } + + if (m_processor->ready()) { + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "Complete message received. Dispatching"; + m_alog->write(log::alevel::devel,s.str()); + } + + message_ptr msg = m_processor->get_message(); + + if (!msg) { + m_alog->write(log::alevel::devel, "null message from m_processor"); + } else if (!is_control(msg->get_opcode())) { + // data message, dispatch to user + if (m_state != session::state::open) { + m_elog->write(log::elevel::warn, "got non-close frame while closing"); + } else if (m_message_handler) { + m_message_handler(m_connection_hdl, msg); + } + } else { + process_control_frame(msg); + } + } + } + + read_frame(); +} + +/// Issue a new transport read unless reading is paused. +template +void connection::read_frame() { + if (!m_read_flag) { + return; + } + + transport_con_type::async_read_at_least( + // std::min wont work with undefined static const values. + // TODO: is there a more elegant way to do this? + // Need to determine if requesting 1 byte or the exact number of bytes + // is better here. 1 byte lets us be a bit more responsive at a + // potential expense of additional runs through handle_read_frame + /*(m_processor->get_bytes_needed() > config::connection_read_buffer_size ? + config::connection_read_buffer_size : m_processor->get_bytes_needed())*/ + 1, + m_buf, + config::connection_read_buffer_size, + m_handle_read_frame + ); +} + +template +lib::error_code connection::initialize_processor() { + m_alog->write(log::alevel::devel,"initialize_processor"); + + // if it isn't a websocket handshake nothing to do. + if (!processor::is_websocket_handshake(m_request)) { + return lib::error_code(); + } + + int version = processor::get_websocket_version(m_request); + + if (version < 0) { + m_alog->write(log::alevel::devel, "BAD REQUEST: can't determine version"); + m_response.set_status(http::status_code::bad_request); + return error::make_error_code(error::invalid_version); + } + + m_processor = get_processor(version); + + // if the processor is not null we are done + if (m_processor) { + return lib::error_code(); + } + + // We don't have a processor for this version. Return bad request + // with Sec-WebSocket-Version header filled with values we do accept + m_alog->write(log::alevel::devel, "BAD REQUEST: no processor for version"); + m_response.set_status(http::status_code::bad_request); + + std::stringstream ss; + std::string sep; + std::vector::const_iterator it; + for (it = versions_supported.begin(); it != versions_supported.end(); it++) + { + ss << sep << *it; + sep = ","; + } + + m_response.replace_header("Sec-WebSocket-Version",ss.str()); + return error::make_error_code(error::unsupported_version); +} + +template +lib::error_code connection::process_handshake_request() { + m_alog->write(log::alevel::devel,"process handshake request"); + + if (!processor::is_websocket_handshake(m_request)) { + // this is not a websocket handshake. Process as plain HTTP + m_alog->write(log::alevel::devel,"HTTP REQUEST"); + + // extract URI from request + m_uri = processor::get_uri_from_host( + m_request, + (transport_con_type::is_secure() ? "https" : "http") + ); + + if (!m_uri->get_valid()) { + m_alog->write(log::alevel::devel, "Bad request: failed to parse uri"); + m_response.set_status(http::status_code::bad_request); + return error::make_error_code(error::invalid_uri); + } + + if (m_http_handler) { + m_is_http = true; + m_http_handler(m_connection_hdl); + + if (m_state == session::state::closed) { + return error::make_error_code(error::http_connection_ended); + } + } else { + set_status(http::status_code::upgrade_required); + return error::make_error_code(error::upgrade_required); + } + + return lib::error_code(); + } + + lib::error_code ec = m_processor->validate_handshake(m_request); + + // Validate: make sure all required elements are present. + if (ec){ + // Not a valid handshake request + m_alog->write(log::alevel::devel, "Bad request " + ec.message()); + m_response.set_status(http::status_code::bad_request); + return ec; + } + + // Read extension parameters and set up values necessary for the end user + // to complete extension negotiation. + std::pair neg_results; + neg_results = m_processor->negotiate_extensions(m_request); + + if (neg_results.first == processor::error::make_error_code(processor::error::extension_parse_error)) { + // There was a fatal error in extension parsing that should result in + // a failed connection attempt. + m_elog->write(log::elevel::info, "Bad request: " + neg_results.first.message()); + m_response.set_status(http::status_code::bad_request); + return neg_results.first; + } else if (neg_results.first) { + // There was a fatal error in extension processing that is probably our + // fault. Consider extension negotiation to have failed and continue as + // if extensions were not supported + m_elog->write(log::elevel::info, + "Extension negotiation failed: " + neg_results.first.message()); + } else { + // extension negotiation succeeded, set response header accordingly + // we don't send an empty extensions header because it breaks many + // clients. + if (neg_results.second.size() > 0) { + m_response.replace_header("Sec-WebSocket-Extensions", + neg_results.second); + } + } + + // extract URI from request + m_uri = m_processor->get_uri(m_request); + + + if (!m_uri->get_valid()) { + m_alog->write(log::alevel::devel, "Bad request: failed to parse uri"); + m_response.set_status(http::status_code::bad_request); + return error::make_error_code(error::invalid_uri); + } + + // extract subprotocols + lib::error_code subp_ec = m_processor->extract_subprotocols(m_request, + m_requested_subprotocols); + + if (subp_ec) { + // should we do anything? + } + + // Ask application to validate the connection + if (!m_validate_handler || m_validate_handler(m_connection_hdl)) { + m_response.set_status(http::status_code::switching_protocols); + + // Write the appropriate response headers based on request and + // processor version + ec = m_processor->process_handshake(m_request,m_subprotocol,m_response); + + if (ec) { + std::stringstream s; + s << "Processing error: " << ec << "(" << ec.message() << ")"; + m_alog->write(log::alevel::devel, s.str()); + + m_response.set_status(http::status_code::internal_server_error); + return ec; + } + } else { + // User application has rejected the handshake + m_alog->write(log::alevel::devel, "USER REJECT"); + + // Use Bad Request if the user handler did not provide a more + // specific http response error code. + // TODO: is there a better default? + if (m_response.get_status_code() == http::status_code::uninitialized) { + m_response.set_status(http::status_code::bad_request); + } + + return error::make_error_code(error::rejected); + } + + return lib::error_code(); +} + +template +void connection::write_http_response(lib::error_code const & ec) { + m_alog->write(log::alevel::devel,"connection write_http_response"); + + if (ec == error::make_error_code(error::http_connection_ended)) { + m_alog->write(log::alevel::http,"An HTTP handler took over the connection."); + return; + } + + if (m_response.get_status_code() == http::status_code::uninitialized) { + m_response.set_status(http::status_code::internal_server_error); + m_ec = error::make_error_code(error::general); + } else { + m_ec = ec; + } + + m_response.set_version("HTTP/1.1"); + + // Set server header based on the user agent settings + if (m_response.get_header("Server").empty()) { + if (!m_user_agent.empty()) { + m_response.replace_header("Server",m_user_agent); + } else { + m_response.remove_header("Server"); + } + } + + // have the processor generate the raw bytes for the wire (if it exists) + if (m_processor) { + m_handshake_buffer = m_processor->get_raw(m_response); + } else { + // a processor wont exist for raw HTTP responses. + m_handshake_buffer = m_response.raw(); + } + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer); + if (!m_response.get_header("Sec-WebSocket-Key3").empty()) { + m_alog->write(log::alevel::devel, + utility::to_hex(m_response.get_header("Sec-WebSocket-Key3"))); + } + } + + // write raw bytes + transport_con_type::async_write( + m_handshake_buffer.data(), + m_handshake_buffer.size(), + lib::bind( + &type::handle_write_http_response, + type::get_shared(), + lib::placeholders::_1 + ) + ); +} + +template +void connection::handle_write_http_response(lib::error_code const & ec) { + m_alog->write(log::alevel::devel,"handle_write_http_response"); + + lib::error_code ecm = ec; + + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog->write(log::alevel::devel, + "handle_write_http_response invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } + } + + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog->write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_write_http_response",ecm); + this->terminate(ecm); + return; + } + + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + + if (m_response.get_status_code() != http::status_code::switching_protocols) + { + /*if (m_processor || m_ec == error::http_parse_error || + m_ec == error::invalid_version || m_ec == error::unsupported_version + || m_ec == error::upgrade_required) + {*/ + if (!m_is_http) { + std::stringstream s; + s << "Handshake ended with HTTP error: " + << m_response.get_status_code(); + m_elog->write(log::elevel::rerror,s.str()); + } else { + // if this was not a websocket connection, we have written + // the expected response and the connection can be closed. + + this->log_http_result(); + + if (m_ec) { + m_alog->write(log::alevel::devel, + "got to writing HTTP results with m_ec set: "+m_ec.message()); + } + m_ec = make_error_code(error::http_connection_ended); + } + + this->terminate(m_ec); + return; + } + + this->log_open_result(); + + m_internal_state = istate::PROCESS_CONNECTION; + m_state = session::state::open; + + if (m_open_handler) { + m_open_handler(m_connection_hdl); + } + + this->handle_read_frame(lib::error_code(), m_buf_cursor); +} + +template +void connection::send_http_request() { + m_alog->write(log::alevel::devel,"connection send_http_request"); + + // TODO: origin header? + + // Have the protocol processor fill in the appropriate fields based on the + // selected client version + if (m_processor) { + lib::error_code ec; + ec = m_processor->client_handshake_request(m_request,m_uri, + m_requested_subprotocols); + + if (ec) { + log_err(log::elevel::fatal,"Internal library error: Processor",ec); + return; + } + } else { + m_elog->write(log::elevel::fatal,"Internal library error: missing processor"); + return; + } + + // Unless the user has overridden the user agent, send generic WS++ UA. + if (m_request.get_header("User-Agent").empty()) { + if (!m_user_agent.empty()) { + m_request.replace_header("User-Agent",m_user_agent); + } else { + m_request.remove_header("User-Agent"); + } + } + + m_handshake_buffer = m_request.raw(); + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer); + } + + if (m_open_handshake_timeout_dur > 0) { + m_handshake_timer = transport_con_type::set_timer( + m_open_handshake_timeout_dur, + lib::bind( + &type::handle_open_handshake_timeout, + type::get_shared(), + lib::placeholders::_1 + ) + ); + } + + transport_con_type::async_write( + m_handshake_buffer.data(), + m_handshake_buffer.size(), + lib::bind( + &type::handle_send_http_request, + type::get_shared(), + lib::placeholders::_1 + ) + ); +} + +template +void connection::handle_send_http_request(lib::error_code const & ec) { + m_alog->write(log::alevel::devel,"handle_send_http_request"); + + lib::error_code ecm = ec; + + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::WRITE_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } else { + m_internal_state = istate::READ_HTTP_RESPONSE; + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog->write(log::alevel::devel, + "handle_send_http_request invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } + } + + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog->write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_send_http_request",ecm); + this->terminate(ecm); + return; + } + + transport_con_type::async_read_at_least( + 1, + m_buf, + config::connection_read_buffer_size, + lib::bind( + &type::handle_read_http_response, + type::get_shared(), + lib::placeholders::_1, + lib::placeholders::_2 + ) + ); +} + +template +void connection::handle_read_http_response(lib::error_code const & ec, + size_t bytes_transferred) +{ + m_alog->write(log::alevel::devel,"handle_read_http_response"); + + lib::error_code ecm = ec; + + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::READ_HTTP_RESPONSE) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog->write(log::alevel::devel, + "handle_read_http_response invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } + } + + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog->write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_read_http_response",ecm); + this->terminate(ecm); + return; + } + + size_t bytes_processed = 0; + // TODO: refactor this to use error codes rather than exceptions + try { + bytes_processed = m_response.consume(m_buf,bytes_transferred); + } catch (http::exception & e) { + m_elog->write(log::elevel::rerror, + std::string("error in handle_read_http_response: ")+e.what()); + this->terminate(make_error_code(error::general)); + return; + } + + m_alog->write(log::alevel::devel,std::string("Raw response: ")+m_response.raw()); + + if (m_response.headers_ready()) { + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + + lib::error_code validate_ec = m_processor->validate_server_handshake_response( + m_request, + m_response + ); + if (validate_ec) { + log_err(log::elevel::rerror,"Server handshake response",validate_ec); + this->terminate(validate_ec); + return; + } + + // Read extension parameters and set up values necessary for the end + // user to complete extension negotiation. + std::pair neg_results; + neg_results = m_processor->negotiate_extensions(m_response); + + if (neg_results.first) { + // There was a fatal error in extension negotiation. For the moment + // kill all connections that fail extension negotiation. + + // TODO: deal with cases where the response is well formed but + // doesn't match the options requested by the client. Its possible + // that the best behavior in this cases is to log and continue with + // an unextended connection. + m_alog->write(log::alevel::devel, "Extension negotiation failed: " + + neg_results.first.message()); + this->terminate(make_error_code(error::extension_neg_failed)); + // TODO: close connection with reason 1010 (and list extensions) + } + + // response is valid, connection can now be assumed to be open + m_internal_state = istate::PROCESS_CONNECTION; + m_state = session::state::open; + + this->log_open_result(); + + if (m_open_handler) { + m_open_handler(m_connection_hdl); + } + + // The remaining bytes in m_buf are frame data. Copy them to the + // beginning of the buffer and note the length. They will be read after + // the handshake completes and before more bytes are read. + std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf); + m_buf_cursor = bytes_transferred-bytes_processed; + + this->handle_read_frame(lib::error_code(), m_buf_cursor); + } else { + transport_con_type::async_read_at_least( + 1, + m_buf, + config::connection_read_buffer_size, + lib::bind( + &type::handle_read_http_response, + type::get_shared(), + lib::placeholders::_1, + lib::placeholders::_2 + ) + ); + } +} + +template +void connection::handle_open_handshake_timeout( + lib::error_code const & ec) +{ + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel,"open handshake timer cancelled"); + } else if (ec) { + m_alog->write(log::alevel::devel, + "open handle_open_handshake_timeout error: "+ec.message()); + // TODO: ignore or fail here? + } else { + m_alog->write(log::alevel::devel,"open handshake timer expired"); + terminate(make_error_code(error::open_handshake_timeout)); + } +} + +template +void connection::handle_close_handshake_timeout( + lib::error_code const & ec) +{ + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel,"asio close handshake timer cancelled"); + } else if (ec) { + m_alog->write(log::alevel::devel, + "asio open handle_close_handshake_timeout error: "+ec.message()); + // TODO: ignore or fail here? + } else { + m_alog->write(log::alevel::devel, "asio close handshake timer expired"); + terminate(make_error_code(error::close_handshake_timeout)); + } +} + +template +void connection::terminate(lib::error_code const & ec) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection terminate"); + } + + // Cancel close handshake timer + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + + terminate_status tstat = unknown; + if (ec) { + m_ec = ec; + m_local_close_code = close::status::abnormal_close; + m_local_close_reason = ec.message(); + } + + // TODO: does any of this need a mutex? + if (m_is_http) { + m_http_state = session::http_state::closed; + } + if (m_state == session::state::connecting) { + m_state = session::state::closed; + tstat = failed; + + // Log fail result here before socket is shut down and we can't get + // the remote address, etc anymore + if (m_ec != error::http_connection_ended) { + log_fail_result(); + } + } else if (m_state != session::state::closed) { + m_state = session::state::closed; + tstat = closed; + } else { + m_alog->write(log::alevel::devel, + "terminate called on connection that was already terminated"); + return; + } + + // TODO: choose between shutdown and close based on error code sent + + transport_con_type::async_shutdown( + lib::bind( + &type::handle_terminate, + type::get_shared(), + tstat, + lib::placeholders::_1 + ) + ); +} + +template +void connection::handle_terminate(terminate_status tstat, + lib::error_code const & ec) +{ + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection handle_terminate"); + } + + if (ec) { + // there was an error actually shutting down the connection + log_err(log::elevel::devel,"handle_terminate",ec); + } + + // clean shutdown + if (tstat == failed) { + if (m_ec != error::http_connection_ended) { + if (m_fail_handler) { + m_fail_handler(m_connection_hdl); + } + } + } else if (tstat == closed) { + if (m_close_handler) { + m_close_handler(m_connection_hdl); + } + log_close_result(); + } else { + m_elog->write(log::elevel::rerror,"Unknown terminate_status"); + } + + // call the termination handler if it exists + // if it exists it might (but shouldn't) refer to a bad memory location. + // If it does, we don't care and should catch and ignore it. + if (m_termination_handler) { + try { + m_termination_handler(type::get_shared()); + } catch (std::exception const & e) { + m_elog->write(log::elevel::warn, + std::string("termination_handler call failed. Reason was: ")+e.what()); + } + } +} + +template +void connection::write_frame() { + //m_alog->write(log::alevel::devel,"connection write_frame"); + + { + scoped_lock_type lock(m_write_lock); + + // Check the write flag. If true, there is an outstanding transport + // write already. In this case we just return. The write handler will + // start a new write if the write queue isn't empty. If false, we set + // the write flag and proceed to initiate a transport write. + if (m_write_flag) { + return; + } + + // pull off all the messages that are ready to write. + // stop if we get a message marked terminal + message_ptr next_message = write_pop(); + while (next_message) { + m_current_msgs.push_back(next_message); + if (!next_message->get_terminal()) { + next_message = write_pop(); + } else { + next_message = message_ptr(); + } + } + + if (m_current_msgs.empty()) { + // there was nothing to send + return; + } else { + // At this point we own the next messages to be sent and are + // responsible for holding the write flag until they are + // successfully sent or there is some error + m_write_flag = true; + } + } + + typename std::vector::iterator it; + for (it = m_current_msgs.begin(); it != m_current_msgs.end(); ++it) { + std::string const & header = (*it)->get_header(); + std::string const & payload = (*it)->get_payload(); + + m_send_buffer.push_back(transport::buffer(header.c_str(),header.size())); + m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size())); + } + + // Print detailed send stats if those log levels are enabled + if (m_alog->static_test(log::alevel::frame_header)) { + if (m_alog->dynamic_test(log::alevel::frame_header)) { + std::stringstream general,header,payload; + + general << "Dispatching write containing " << m_current_msgs.size() + <<" message(s) containing "; + header << "Header Bytes: \n"; + payload << "Payload Bytes: \n"; + + size_t hbytes = 0; + size_t pbytes = 0; + + for (size_t i = 0; i < m_current_msgs.size(); i++) { + hbytes += m_current_msgs[i]->get_header().size(); + pbytes += m_current_msgs[i]->get_payload().size(); + + + header << "[" << i << "] (" + << m_current_msgs[i]->get_header().size() << ") " + << utility::to_hex(m_current_msgs[i]->get_header()) << "\n"; + + if (m_alog->static_test(log::alevel::frame_payload)) { + if (m_alog->dynamic_test(log::alevel::frame_payload)) { + payload << "[" << i << "] (" + << m_current_msgs[i]->get_payload().size() << ") ["<get_opcode()<<"] " + << (m_current_msgs[i]->get_opcode() == frame::opcode::text ? + m_current_msgs[i]->get_payload() : + utility::to_hex(m_current_msgs[i]->get_payload()) + ) + << "\n"; + } + } + } + + general << hbytes << " header bytes and " << pbytes << " payload bytes"; + + m_alog->write(log::alevel::frame_header,general.str()); + m_alog->write(log::alevel::frame_header,header.str()); + m_alog->write(log::alevel::frame_payload,payload.str()); + } + } + + transport_con_type::async_write( + m_send_buffer, + m_write_frame_handler + ); +} + +template +void connection::handle_write_frame(lib::error_code const & ec) +{ + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"connection handle_write_frame"); + } + + bool terminal = m_current_msgs.back()->get_terminal(); + + m_send_buffer.clear(); + m_current_msgs.clear(); + // TODO: recycle instead of deleting + + if (ec) { + log_err(log::elevel::fatal,"handle_write_frame",ec); + this->terminate(ec); + return; + } + + if (terminal) { + this->terminate(lib::error_code()); + return; + } + + bool needs_writing = false; + { + scoped_lock_type lock(m_write_lock); + + // release write flag + m_write_flag = false; + + needs_writing = !m_send_queue.empty(); + } + + if (needs_writing) { + transport_con_type::dispatch(lib::bind( + &type::write_frame, + type::get_shared() + )); + } +} + +template +std::vector const & connection::get_supported_versions() const +{ + return versions_supported; +} + +template +void connection::process_control_frame(typename config::message_type::ptr msg) +{ + m_alog->write(log::alevel::devel,"process_control_frame"); + + frame::opcode::value op = msg->get_opcode(); + lib::error_code ec; + + std::stringstream s; + s << "Control frame received with opcode " << op; + m_alog->write(log::alevel::control,s.str()); + + if (m_state == session::state::closed) { + m_elog->write(log::elevel::warn,"got frame in state closed"); + return; + } + if (op != frame::opcode::CLOSE && m_state != session::state::open) { + m_elog->write(log::elevel::warn,"got non-close frame in state closing"); + return; + } + + if (op == frame::opcode::PING) { + bool should_reply = true; + + if (m_ping_handler) { + should_reply = m_ping_handler(m_connection_hdl, msg->get_payload()); + } + + if (should_reply) { + this->pong(msg->get_payload(),ec); + if (ec) { + log_err(log::elevel::devel,"Failed to send response pong",ec); + } + } + } else if (op == frame::opcode::PONG) { + if (m_pong_handler) { + m_pong_handler(m_connection_hdl, msg->get_payload()); + } + if (m_ping_timer) { + m_ping_timer->cancel(); + } + } else if (op == frame::opcode::CLOSE) { + m_alog->write(log::alevel::devel,"got close frame"); + // record close code and reason somewhere + + m_remote_close_code = close::extract_code(msg->get_payload(),ec); + if (ec) { + s.str(""); + if (config::drop_on_protocol_error) { + s << "Received invalid close code " << m_remote_close_code + << " dropping connection per config."; + m_elog->write(log::elevel::devel,s.str()); + this->terminate(ec); + } else { + s << "Received invalid close code " << m_remote_close_code + << " sending acknowledgement and closing"; + m_elog->write(log::elevel::devel,s.str()); + ec = send_close_ack(close::status::protocol_error, + "Invalid close code"); + if (ec) { + log_err(log::elevel::devel,"send_close_ack",ec); + } + } + return; + } + + m_remote_close_reason = close::extract_reason(msg->get_payload(),ec); + if (ec) { + if (config::drop_on_protocol_error) { + m_elog->write(log::elevel::devel, + "Received invalid close reason. Dropping connection per config"); + this->terminate(ec); + } else { + m_elog->write(log::elevel::devel, + "Received invalid close reason. Sending acknowledgement and closing"); + ec = send_close_ack(close::status::protocol_error, + "Invalid close reason"); + if (ec) { + log_err(log::elevel::devel,"send_close_ack",ec); + } + } + return; + } + + if (m_state == session::state::open) { + s.str(""); + s << "Received close frame with code " << m_remote_close_code + << " and reason " << m_remote_close_reason; + m_alog->write(log::alevel::devel,s.str()); + + ec = send_close_ack(); + if (ec) { + log_err(log::elevel::devel,"send_close_ack",ec); + } + } else if (m_state == session::state::closing && !m_was_clean) { + // ack of our close + m_alog->write(log::alevel::devel, "Got acknowledgement of close"); + + m_was_clean = true; + + // If we are a server terminate the connection now. Clients should + // leave the connection open to give the server an opportunity to + // initiate the TCP close. The client's timer will handle closing + // its side of the connection if the server misbehaves. + // + // TODO: different behavior if the underlying transport doesn't + // support timers? + if (m_is_server) { + terminate(lib::error_code()); + } + } else { + // spurious, ignore + m_elog->write(log::elevel::devel, "Got close frame in wrong state"); + } + } else { + // got an invalid control opcode + m_elog->write(log::elevel::devel, "Got control frame with invalid opcode"); + // initiate protocol error shutdown + } +} + +template +lib::error_code connection::send_close_ack(close::status::value code, + std::string const & reason) +{ + return send_close_frame(code,reason,true,m_is_server); +} + +template +lib::error_code connection::send_close_frame(close::status::value code, + std::string const & reason, bool ack, bool terminal) +{ + m_alog->write(log::alevel::devel,"send_close_frame"); + + // check for special codes + + // If silent close is set, respect it and blank out close information + // Otherwise use whatever has been specified in the parameters. If + // parameters specifies close::status::blank then determine what to do + // based on whether or not this is an ack. If it is not an ack just + // send blank info. If it is an ack then echo the close information from + // the remote endpoint. + if (config::silent_close) { + m_alog->write(log::alevel::devel,"closing silently"); + m_local_close_code = close::status::no_status; + m_local_close_reason.clear(); + } else if (code != close::status::blank) { + m_alog->write(log::alevel::devel,"closing with specified codes"); + m_local_close_code = code; + m_local_close_reason = reason; + } else if (!ack) { + m_alog->write(log::alevel::devel,"closing with no status code"); + m_local_close_code = close::status::no_status; + m_local_close_reason.clear(); + } else if (m_remote_close_code == close::status::no_status) { + m_alog->write(log::alevel::devel, + "acknowledging a no-status close with normal code"); + m_local_close_code = close::status::normal; + m_local_close_reason.clear(); + } else { + m_alog->write(log::alevel::devel,"acknowledging with remote codes"); + m_local_close_code = m_remote_close_code; + m_local_close_reason = m_remote_close_reason; + } + + std::stringstream s; + s << "Closing with code: " << m_local_close_code << ", and reason: " + << m_local_close_reason; + m_alog->write(log::alevel::devel,s.str()); + + message_ptr msg = m_msg_manager->get_message(); + if (!msg) { + return error::make_error_code(error::no_outgoing_buffers); + } + + lib::error_code ec = m_processor->prepare_close(m_local_close_code, + m_local_close_reason,msg); + if (ec) { + return ec; + } + + // Messages flagged terminal will result in the TCP connection being dropped + // after the message has been written. This is typically used when servers + // send an ack and when any endpoint encounters a protocol error + if (terminal) { + msg->set_terminal(true); + } + + m_state = session::state::closing; + + if (ack) { + m_was_clean = true; + } + + // Start a timer so we don't wait forever for the acknowledgement close + // frame + if (m_close_handshake_timeout_dur > 0) { + m_handshake_timer = transport_con_type::set_timer( + m_close_handshake_timeout_dur, + lib::bind( + &type::handle_close_handshake_timeout, + type::get_shared(), + lib::placeholders::_1 + ) + ); + } + + bool needs_writing = false; + { + scoped_lock_type lock(m_write_lock); + write_push(msg); + needs_writing = !m_write_flag && !m_send_queue.empty(); + } + + if (needs_writing) { + transport_con_type::dispatch(lib::bind( + &type::write_frame, + type::get_shared() + )); + } + + return lib::error_code(); +} + +template +typename connection::processor_ptr +connection::get_processor(int version) const { + // TODO: allow disabling certain versions + + processor_ptr p; + + switch (version) { + case 0: + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager + ); + break; + case 7: + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) + ); + break; + case 8: + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) + ); + break; + case 13: + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) + ); + break; + default: + return p; + } + + // Settings not configured by the constructor + p->set_max_message_size(m_max_message_size); + + return p; +} + +template +void connection::write_push(typename config::message_type::ptr msg) +{ + if (!msg) { + return; + } + + m_send_buffer_size += msg->get_payload().size(); + m_send_queue.push(msg); + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "write_push: message count: " << m_send_queue.size() + << " buffer size: " << m_send_buffer_size; + m_alog->write(log::alevel::devel,s.str()); + } +} + +template +typename config::message_type::ptr connection::write_pop() +{ + message_ptr msg; + + if (m_send_queue.empty()) { + return msg; + } + + msg = m_send_queue.front(); + + m_send_buffer_size -= msg->get_payload().size(); + m_send_queue.pop(); + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "write_pop: message count: " << m_send_queue.size() + << " buffer size: " << m_send_buffer_size; + m_alog->write(log::alevel::devel,s.str()); + } + return msg; +} + +template +void connection::log_open_result() +{ + std::stringstream s; + + int version; + if (!processor::is_websocket_handshake(m_request)) { + version = -1; + } else { + version = processor::get_websocket_version(m_request); + } + + // Connection Type + s << (version == -1 ? "HTTP" : "WebSocket") << " Connection "; + + // Remote endpoint address + s << transport_con_type::get_remote_endpoint() << " "; + + // Version string if WebSocket + if (version != -1) { + s << "v" << version << " "; + } + + // User Agent + std::string ua = m_request.get_header("User-Agent"); + if (ua.empty()) { + s << "\"\" "; + } else { + // check if there are any quotes in the user agent + s << "\"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; + } + + // URI + s << (m_uri ? m_uri->get_resource() : "NULL") << " "; + + // Status code + s << m_response.get_status_code(); + + m_alog->write(log::alevel::connect,s.str()); +} + +template +void connection::log_close_result() +{ + std::stringstream s; + + s << "Disconnect " + << "close local:[" << m_local_close_code + << (m_local_close_reason.empty() ? "" : ","+m_local_close_reason) + << "] remote:[" << m_remote_close_code + << (m_remote_close_reason.empty() ? "" : ","+m_remote_close_reason) << "]"; + + m_alog->write(log::alevel::disconnect,s.str()); +} + +template +void connection::log_fail_result() +{ + std::stringstream s; + + int version = processor::get_websocket_version(m_request); + + // Connection Type + s << "WebSocket Connection "; + + // Remote endpoint address & WebSocket version + s << transport_con_type::get_remote_endpoint(); + if (version < 0) { + s << " -"; + } else { + s << " v" << version; + } + + // User Agent + std::string ua = m_request.get_header("User-Agent"); + if (ua.empty()) { + s << " \"\" "; + } else { + // check if there are any quotes in the user agent + s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; + } + + // URI + s << (m_uri ? m_uri->get_resource() : "-"); + + // HTTP Status code + s << " " << m_response.get_status_code(); + + // WebSocket++ error code & reason + s << " " << m_ec << " " << m_ec.message(); + + m_alog->write(log::alevel::fail,s.str()); +} + +template +void connection::log_http_result() { + std::stringstream s; + + if (processor::is_websocket_handshake(m_request)) { + m_alog->write(log::alevel::devel,"Call to log_http_result for WebSocket"); + return; + } + + // Connection Type + s << (m_request.get_header("host").empty() ? "-" : m_request.get_header("host")) + << " " << transport_con_type::get_remote_endpoint() + << " \"" << m_request.get_method() + << " " << (m_uri ? m_uri->get_resource() : "-") + << " " << m_request.get_version() << "\" " << m_response.get_status_code() + << " " << m_response.get_body().size(); + + // User Agent + std::string ua = m_request.get_header("User-Agent"); + if (ua.empty()) { + s << " \"\" "; + } else { + // check if there are any quotes in the user agent + s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; + } + + m_alog->write(log::alevel::http,s.str()); +} + +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONNECTION_IMPL_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/impl/endpoint_impl.hpp b/thirdparty/websocketpp/include/websocketpp/impl/endpoint_impl.hpp index 3b2136d..2aac1d9 100644 --- a/thirdparty/websocketpp/include/websocketpp/impl/endpoint_impl.hpp +++ b/thirdparty/websocketpp/include/websocketpp/impl/endpoint_impl.hpp @@ -1,269 +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 - -namespace websocketpp { - -template -typename endpoint::connection_ptr -endpoint::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(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(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 -void endpoint::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 -void endpoint::interrupt(connection_hdl hdl) { - lib::error_code ec; - interrupt(hdl,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::pause_reading(connection_hdl hdl) { - lib::error_code ec; - pause_reading(hdl,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::resume_reading(connection_hdl hdl) { - lib::error_code ec; - resume_reading(hdl,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::send_http_response(connection_hdl hdl) { - lib::error_code ec; - send_http_response(hdl,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::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 -void endpoint::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 -void endpoint::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 -void endpoint::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 -void endpoint::send(connection_hdl hdl, message_ptr msg) { - lib::error_code ec; - send(hdl,msg,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::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 -void endpoint::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 -void endpoint::ping(connection_hdl hdl, std::string const & payload) -{ - lib::error_code ec; - ping(hdl,payload,ec); - if (ec) { throw exception(ec); } -} - -template -void endpoint::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 -void endpoint::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 +/* + * 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 + +namespace websocketpp { + +template +typename endpoint::connection_ptr +endpoint::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(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(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 +void endpoint::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 +void endpoint::interrupt(connection_hdl hdl) { + lib::error_code ec; + interrupt(hdl,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::pause_reading(connection_hdl hdl) { + lib::error_code ec; + pause_reading(hdl,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::resume_reading(connection_hdl hdl) { + lib::error_code ec; + resume_reading(hdl,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::send_http_response(connection_hdl hdl) { + lib::error_code ec; + send_http_response(hdl,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::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 +void endpoint::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 +void endpoint::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 +void endpoint::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 +void endpoint::send(connection_hdl hdl, message_ptr msg) { + lib::error_code ec; + send(hdl,msg,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::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 +void endpoint::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 +void endpoint::ping(connection_hdl hdl, std::string const & payload) +{ + lib::error_code ec; + ping(hdl,payload,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::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 +void endpoint::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 diff --git a/thirdparty/websocketpp/include/websocketpp/impl/utilities_impl.hpp b/thirdparty/websocketpp/include/websocketpp/impl/utilities_impl.hpp index 4da3fb7..6f86e22 100644 --- a/thirdparty/websocketpp/include/websocketpp/impl/utilities_impl.hpp +++ b/thirdparty/websocketpp/include/websocketpp/impl/utilities_impl.hpp @@ -1,87 +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 -#include - -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(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 +/* + * 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 +#include + +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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/logger/basic.hpp b/thirdparty/websocketpp/include/websocketpp/logger/basic.hpp index a61e4b9..8451413 100644 --- a/thirdparty/websocketpp/include/websocketpp/logger/basic.hpp +++ b/thirdparty/websocketpp/include/websocketpp/logger/basic.hpp @@ -1,199 +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 - -#include -#include -#include - -#include -#include -#include -#include - -namespace websocketpp { -namespace log { - -/// Basic logger that outputs to an ostream -template -class basic { -public: - basic(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(std::ostream * out) - : m_static_channels(0xffffffff) - , m_dynamic_channels(0) - , m_out(out) {} - - basic(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(level c, std::ostream * out) - : m_static_channels(c) - , m_dynamic_channels(0) - , m_out(out) {} - - /// Destructor - ~basic() {} - - /// Copy constructor - basic(basic 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 & operator=(basic const &) = delete; -#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - -#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ - /// Move constructor - basic(basic && 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 & operator=(basic &&) = 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(<,"%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",<); - 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 +/* + * 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 + +#include +#include +#include + +#include +#include +#include +#include + +namespace websocketpp { +namespace log { + +/// Basic logger that outputs to an ostream +template +class basic { +public: + basic(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(std::ostream * out) + : m_static_channels(0xffffffff) + , m_dynamic_channels(0) + , m_out(out) {} + + basic(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(level c, std::ostream * out) + : m_static_channels(c) + , m_dynamic_channels(0) + , m_out(out) {} + + /// Destructor + ~basic() {} + + /// Copy constructor + basic(basic 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 & operator=(basic const &) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Move constructor + basic(basic && 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 & operator=(basic &&) = 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(<,"%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",<); + 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 diff --git a/thirdparty/websocketpp/include/websocketpp/logger/levels.hpp b/thirdparty/websocketpp/include/websocketpp/logger/levels.hpp index 3970861..cd7ccd6 100644 --- a/thirdparty/websocketpp/include/websocketpp/logger/levels.hpp +++ b/thirdparty/websocketpp/include/websocketpp/logger/levels.hpp @@ -1,203 +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 - -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 +/* + * 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 + +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 diff --git a/thirdparty/websocketpp/include/websocketpp/logger/stub.hpp b/thirdparty/websocketpp/include/websocketpp/logger/stub.hpp index cc4da33..2db6da7 100644 --- a/thirdparty/websocketpp/include/websocketpp/logger/stub.hpp +++ b/thirdparty/websocketpp/include/websocketpp/logger/stub.hpp @@ -1,119 +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 - -#include - -#include - -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 +/* + * 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 + +#include + +#include + +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 diff --git a/thirdparty/websocketpp/include/websocketpp/logger/syslog.hpp b/thirdparty/websocketpp/include/websocketpp/logger/syslog.hpp index 7cb82ae..513abee 100644 --- a/thirdparty/websocketpp/include/websocketpp/logger/syslog.hpp +++ b/thirdparty/websocketpp/include/websocketpp/logger/syslog.hpp @@ -1,146 +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 - -#include - -#include -#include - -namespace websocketpp { -namespace log { - -/// Basic logger that outputs to syslog -template -class syslog : public basic { -public: - typedef basic base; - - /// Construct the logger - /** - * @param hint A channel type specific hint for how to construct the logger - */ - syslog(channel_type_hint::value hint = - channel_type_hint::access) - : basic(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(level channels, channel_type_hint::value hint = - channel_type_hint::access) - : basic(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 +/* + * 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 + +#include + +#include +#include + +namespace websocketpp { +namespace log { + +/// Basic logger that outputs to syslog +template +class syslog : public basic { +public: + typedef basic base; + + /// Construct the logger + /** + * @param hint A channel type specific hint for how to construct the logger + */ + syslog(channel_type_hint::value hint = + channel_type_hint::access) + : basic(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(level channels, channel_type_hint::value hint = + channel_type_hint::access) + : basic(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 diff --git a/thirdparty/websocketpp/include/websocketpp/message_buffer/alloc.hpp b/thirdparty/websocketpp/include/websocketpp/message_buffer/alloc.hpp index 92c0a77..75d8976 100644 --- a/thirdparty/websocketpp/include/websocketpp/message_buffer/alloc.hpp +++ b/thirdparty/websocketpp/include/websocketpp/message_buffer/alloc.hpp @@ -1,105 +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 -#include - -namespace websocketpp { -namespace message_buffer { -namespace alloc { - -/// A connection message manager that allocates a new message for each -/// request. -template -class con_msg_manager - : public lib::enable_shared_from_this > -{ -public: - typedef con_msg_manager type; - typedef lib::shared_ptr ptr; - typedef lib::weak_ptr 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(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(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 -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()); - } -}; - -} // namespace alloc -} // namespace message_buffer -} // namespace websocketpp - -#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP +/* + * 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 +#include + +namespace websocketpp { +namespace message_buffer { +namespace alloc { + +/// A connection message manager that allocates a new message for each +/// request. +template +class con_msg_manager + : public lib::enable_shared_from_this > +{ +public: + typedef con_msg_manager type; + typedef lib::shared_ptr ptr; + typedef lib::weak_ptr 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(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(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 +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()); + } +}; + +} // namespace alloc +} // namespace message_buffer +} // namespace websocketpp + +#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/message_buffer/message.hpp b/thirdparty/websocketpp/include/websocketpp/message_buffer/message.hpp index c70a736..da36e20 100644 --- a/thirdparty/websocketpp/include/websocketpp/message_buffer/message.hpp +++ b/thirdparty/websocketpp/include/websocketpp/message_buffer/message.hpp @@ -1,340 +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 -#include - -#include - -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 class con_msg_manager> -class message { -public: - typedef lib::shared_ptr ptr; - - typedef con_msg_manager 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(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(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 +/* + * 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 +#include + +#include + +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 class con_msg_manager> +class message { +public: + typedef lib::shared_ptr ptr; + + typedef con_msg_manager 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(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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/message_buffer/pool.hpp b/thirdparty/websocketpp/include/websocketpp/message_buffer/pool.hpp index f231268..3af9e02 100644 --- a/thirdparty/websocketpp/include/websocketpp/message_buffer/pool.hpp +++ b/thirdparty/websocketpp/include/websocketpp/message_buffer/pool.hpp @@ -1,229 +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 - -#include - -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 -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 -class message { -public: - typedef lib::shared_ptr 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 -class con_msg_manager { -public: - typedef lib::shared_ptr ptr; - typedef lib::weak_ptr 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(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 -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(); - } -}; - -} // 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 +/* + * 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 + +#include + +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 +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 +class message { +public: + typedef lib::shared_ptr 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 +class con_msg_manager { +public: + typedef lib::shared_ptr ptr; + typedef lib::weak_ptr 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(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 +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(); + } +}; + +} // 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 diff --git a/thirdparty/websocketpp/include/websocketpp/processors/base.hpp b/thirdparty/websocketpp/include/websocketpp/processors/base.hpp index 79e291c..4c123df 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/base.hpp @@ -1,299 +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 -#include -#include - -#include -#include - -#include - -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(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 -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif //WEBSOCKETPP_PROCESSOR_BASE_HPP +/* + * 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 +#include +#include + +#include +#include + +#include + +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(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 +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif //WEBSOCKETPP_PROCESSOR_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/processors/hybi00.hpp b/thirdparty/websocketpp/include/websocketpp/processors/hybi00.hpp index 1fba38f..95ad9df 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/hybi00.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/hybi00.hpp @@ -1,462 +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 -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace websocketpp { -namespace processor { - -/// Processor for Hybi Draft version 00 -/** - * There are many differences between Hybi 00 and Hybi 13 - */ -template -class hybi00 : public processor { -public: - typedef processor 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(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(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 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 & 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(base::m_secure, h, request.get_uri()); - } else { - return lib::make_shared(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(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(&msg_hdr),1)); - - // process payload - out->set_payload(i); - out->append_payload(std::string(reinterpret_cast(&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(strtoul(digits.c_str(), NULL, 10)); - if (spaces > 0 && num > 0) { - num = htonl(num/spaces); - std::copy(reinterpret_cast(&num), - reinterpret_cast(&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 +/* + * 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 +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace websocketpp { +namespace processor { + +/// Processor for Hybi Draft version 00 +/** + * There are many differences between Hybi 00 and Hybi 13 + */ +template +class hybi00 : public processor { +public: + typedef processor 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(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(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 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 & 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(base::m_secure, h, request.get_uri()); + } else { + return lib::make_shared(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(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(&msg_hdr),1)); + + // process payload + out->set_payload(i); + out->append_payload(std::string(reinterpret_cast(&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(strtoul(digits.c_str(), NULL, 10)); + if (spaces > 0 && num > 0) { + num = htonl(num/spaces); + std::copy(reinterpret_cast(&num), + reinterpret_cast(&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 diff --git a/thirdparty/websocketpp/include/websocketpp/processors/hybi07.hpp b/thirdparty/websocketpp/include/websocketpp/processors/hybi07.hpp index dfa6ace..14b67c2 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/hybi07.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/hybi07.hpp @@ -1,78 +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 - -#include -#include - -namespace websocketpp { -namespace processor { - -/// Processor for Hybi Draft version 07 -/** - * The primary difference between 07 and 08 is a version number. - */ -template -class hybi07 : public hybi08 { -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(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 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 +/* + * 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 + +#include +#include + +namespace websocketpp { +namespace processor { + +/// Processor for Hybi Draft version 07 +/** + * The primary difference between 07 and 08 is a version number. + */ +template +class hybi07 : public hybi08 { +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(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 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 diff --git a/thirdparty/websocketpp/include/websocketpp/processors/hybi08.hpp b/thirdparty/websocketpp/include/websocketpp/processors/hybi08.hpp index 531fcc8..15f6e65 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/hybi08.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/hybi08.hpp @@ -1,83 +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 - -#include -#include - -namespace websocketpp { -namespace processor { - -/// Processor for Hybi Draft version 08 -/** - * The primary difference between 08 and 13 is a different origin header name - */ -template -class hybi08 : public hybi13 { -public: - typedef hybi08 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(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 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 +/* + * 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 + +#include +#include + +namespace websocketpp { +namespace processor { + +/// Processor for Hybi Draft version 08 +/** + * The primary difference between 08 and 13 is a different origin header name + */ +template +class hybi08 : public hybi13 { +public: + typedef hybi08 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(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 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 diff --git a/thirdparty/websocketpp/include/websocketpp/processors/hybi13.hpp b/thirdparty/websocketpp/include/websocketpp/processors/hybi13.hpp index c4c2447..ca12439 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/hybi13.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/hybi13.hpp @@ -1,1078 +1,1078 @@ -/* - * 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_HYBI13_HPP -#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP - -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace websocketpp { -namespace processor { - -/// Processor for Hybi version 13 (RFC6455) -template -class hybi13 : public processor { -public: - typedef processor 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 msg_manager_type; - typedef typename msg_manager_type::ptr msg_manager_ptr; - typedef typename config::rng_type rng_type; - - typedef typename config::permessage_deflate_type permessage_deflate_type; - - typedef std::pair err_str_pair; - - explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng) - : processor(secure, p_is_server) - , m_msg_manager(manager) - , m_rng(rng) - { - reset_headers(); - } - - int get_version() const { - return 13; - } - - bool has_permessage_deflate() const { - return m_permessage_deflate.is_implemented(); - } - - err_str_pair negotiate_extensions(request_type const & request) { - return negotiate_extensions_helper(request); - } - - err_str_pair negotiate_extensions(response_type const & response) { - return negotiate_extensions_helper(response); - } - - /// Extension negotiation helper function - /** - * This exists mostly because the code for requests and responses is - * identical and I can't have virtual template methods. - */ - template - err_str_pair negotiate_extensions_helper(header_type const & header) { - err_str_pair ret; - - // Respect blanket disabling of all extensions and don't even parse - // the extension header - if (!config::enable_extensions) { - ret.first = make_error_code(error::extensions_disabled); - return ret; - } - - http::parameter_list p; - - bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p); - - if (error) { - ret.first = make_error_code(error::extension_parse_error); - return ret; - } - - // If there are no extensions parsed then we are done! - if (p.size() == 0) { - return ret; - } - - http::parameter_list::const_iterator it; - - // look through the list of extension requests to find the first - // one that we can accept. - if (m_permessage_deflate.is_implemented()) { - err_str_pair neg_ret; - for (it = p.begin(); it != p.end(); ++it) { - // not a permessage-deflate extension request, ignore - if (it->first != "permessage-deflate") { - continue; - } - - // if we have already successfully negotiated this extension - // then skip any other requests to negotiate the same one - // with different parameters - if (m_permessage_deflate.is_enabled()) { - continue; - } - - // attempt to negotiate this offer - neg_ret = m_permessage_deflate.negotiate(it->second); - - if (neg_ret.first) { - // negotiation offer failed. Do nothing. We will continue - // searching for a permessage-deflate config that succeeds - continue; - } - - // Negotiation tentatively succeeded - - // Actually try to initialize the extension before we - // deem negotiation complete - lib::error_code ec = m_permessage_deflate.init(base::m_server); - - if (ec) { - // Negotiation succeeded but initialization failed this is - // an error that should stop negotiation of permessage - // deflate. Return the reason for the init failure - - ret.first = ec; - break; - } else { - // Successfully initialized, push the negotiated response into - // the reply and stop looking for additional permessage-deflate - // extensions - ret.second += neg_ret.second; - break; - } - } - } - - // support for future extensions would go here. Should check the value of - // ret.first before continuing. Might need to consider whether failure of - // negotiation of an earlier extension should stop negotiation of subsequent - // ones - - return ret; - } - - 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-Key").empty()) { - return make_error_code(error::missing_required_header); - } - - return lib::error_code(); - } - - /* TODO: the 'subprotocol' parameter may need to be expanded into a more - * generic struct if other user input parameters to the processed handshake - * are found. - */ - lib::error_code process_handshake(request_type const & request, - std::string const & subprotocol, response_type & response) const - { - std::string server_key = request.get_header("Sec-WebSocket-Key"); - - lib::error_code ec = process_handshake_key(server_key); - - if (ec) { - return ec; - } - - response.replace_header("Sec-WebSocket-Accept",server_key); - response.append_header("Upgrade",constants::upgrade_token); - response.append_header("Connection",constants::connection_token); - - if (!subprotocol.empty()) { - response.replace_header("Sec-WebSocket-Protocol",subprotocol); - } - - return lib::error_code(); - } - - /// Fill in a set of request headers for a client connection request - /** - * @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 & req, uri_ptr - uri, std::vector const & subprotocols) const - { - req.set_method("GET"); - req.set_uri(uri->get_resource()); - req.set_version("HTTP/1.1"); - - req.append_header("Upgrade","websocket"); - req.append_header("Connection","Upgrade"); - req.replace_header("Sec-WebSocket-Version","13"); - req.replace_header("Host",uri->get_host_port()); - - if (!subprotocols.empty()) { - std::ostringstream result; - std::vector::const_iterator it = subprotocols.begin(); - result << *it++; - while (it != subprotocols.end()) { - result << ", " << *it++; - } - - req.replace_header("Sec-WebSocket-Protocol",result.str()); - } - - // Generate handshake key - frame::uint32_converter conv; - unsigned char raw_key[16]; - - for (int i = 0; i < 4; i++) { - conv.i = m_rng(); - std::copy(conv.c,conv.c+4,&raw_key[i*4]); - } - - req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16)); - - if (m_permessage_deflate.is_implemented()) { - std::string offer = m_permessage_deflate.generate_offer(); - if (!offer.empty()) { - req.replace_header("Sec-WebSocket-Extensions",offer); - } - } - - return lib::error_code(); - } - - /// 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 - */ - lib::error_code validate_server_handshake_response(request_type const & req, - response_type& res) const - { - // A valid response has an HTTP 101 switching protocols code - if (res.get_status_code() != http::status_code::switching_protocols) { - return error::make_error_code(error::invalid_http_status); - } - - // And the upgrade token in an upgrade header - std::string const & upgrade_header = res.get_header("Upgrade"); - if (utility::ci_find_substr(upgrade_header, constants::upgrade_token, - sizeof(constants::upgrade_token)-1) == upgrade_header.end()) - { - return error::make_error_code(error::missing_required_header); - } - - // And the websocket token in the connection header - std::string const & con_header = res.get_header("Connection"); - if (utility::ci_find_substr(con_header, constants::connection_token, - sizeof(constants::connection_token)-1) == con_header.end()) - { - return error::make_error_code(error::missing_required_header); - } - - // And has a valid Sec-WebSocket-Accept value - std::string key = req.get_header("Sec-WebSocket-Key"); - lib::error_code ec = process_handshake_key(key); - - if (ec || key != res.get_header("Sec-WebSocket-Accept")) { - return error::make_error_code(error::missing_required_header); - } - - // check extensions - - return lib::error_code(); - } - - std::string get_raw(response_type const & res) const { - return res.raw(); - } - - std::string const & get_origin(request_type const & r) const { - return r.get_header("Origin"); - } - - lib::error_code extract_subprotocols(request_type const & req, - std::vector & 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 { - return get_uri_from_host(request,(base::m_secure ? "wss" : "ws")); - } - - /// Process new websocket connection bytes - /** - * - * Hybi 13 data streams represent a series of variable length frames. Each - * frame is made up of a series of fixed length fields. The lengths of later - * fields are contained in earlier fields. The first field length is fixed - * by the spec. - * - * This processor represents a state machine that keeps track of what field - * is presently being read and how many more bytes are needed to complete it - * - * - * - * - * Read two header bytes - * Extract full frame length. - * Read extra header bytes - * Validate frame header (including extension validate) - * Read extension data into extension message state object - * Read payload data into payload - * - * @param buf Input buffer - * - * @param len Length of input buffer - * - * @return Number of bytes processed or zero on error - */ - size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) { - size_t p = 0; - - ec = lib::error_code(); - - //std::cout << "consume: " << utility::to_hex(buf,len) << std::endl; - - // Loop while we don't have a message ready and we still have bytes - // left to process. - while (m_state != READY && m_state != FATAL_ERROR && - (p < len || m_bytes_needed == 0)) - { - if (m_state == HEADER_BASIC) { - p += this->copy_basic_header_bytes(buf+p,len-p); - - if (m_bytes_needed > 0) { - continue; - } - - ec = this->validate_incoming_basic_header( - m_basic_header, base::m_server, !m_data_msg.msg_ptr - ); - if (ec) {break;} - - // extract full header size and adjust consume state accordingly - m_state = HEADER_EXTENDED; - m_cursor = 0; - m_bytes_needed = frame::get_header_len(m_basic_header) - - frame::BASIC_HEADER_LENGTH; - } else if (m_state == HEADER_EXTENDED) { - p += this->copy_extended_header_bytes(buf+p,len-p); - - if (m_bytes_needed > 0) { - continue; - } - - ec = validate_incoming_extended_header(m_basic_header,m_extended_header); - if (ec){break;} - - m_state = APPLICATION; - m_bytes_needed = static_cast(get_payload_size(m_basic_header,m_extended_header)); - - // check if this frame is the start of a new message and set up - // the appropriate message metadata. - frame::opcode::value op = frame::get_opcode(m_basic_header); - - // TODO: get_message failure conditions - - if (frame::opcode::is_control(op)) { - m_control_msg = msg_metadata( - m_msg_manager->get_message(op,m_bytes_needed), - frame::get_masking_key(m_basic_header,m_extended_header) - ); - - m_current_msg = &m_control_msg; - } else { - if (!m_data_msg.msg_ptr) { - if (m_bytes_needed > base::m_max_message_size) { - ec = make_error_code(error::message_too_big); - break; - } - - m_data_msg = msg_metadata( - m_msg_manager->get_message(op,m_bytes_needed), - frame::get_masking_key(m_basic_header,m_extended_header) - ); - - if (m_permessage_deflate.is_enabled()) { - m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header)); - } - } else { - // Fetch the underlying payload buffer from the data message we - // are writing into. - std::string & out = m_data_msg.msg_ptr->get_raw_payload(); - - if (out.size() + m_bytes_needed > base::m_max_message_size) { - ec = make_error_code(error::message_too_big); - break; - } - - // Each frame starts a new masking key. All other state - // remains between frames. - m_data_msg.prepared_key = prepare_masking_key( - frame::get_masking_key( - m_basic_header, - m_extended_header - ) - ); - - out.reserve(out.size() + m_bytes_needed); - } - m_current_msg = &m_data_msg; - } - } else if (m_state == EXTENSION) { - m_state = APPLICATION; - } else if (m_state == APPLICATION) { - size_t bytes_to_process = (std::min)(m_bytes_needed,len-p); - - if (bytes_to_process > 0) { - p += this->process_payload_bytes(buf+p,bytes_to_process,ec); - - if (ec) {break;} - } - - if (m_bytes_needed > 0) { - continue; - } - - // If this was the last frame in the message set the ready flag. - // Otherwise, reset processor state to read additional frames. - if (frame::get_fin(m_basic_header)) { - ec = finalize_message(); - if (ec) { - break; - } - } else { - this->reset_headers(); - } - } else { - // shouldn't be here - ec = make_error_code(error::general); - return 0; - } - } - - return p; - } - - /// Perform any finalization actions on an incoming message - /** - * Called after the full message is received. Provides the opportunity for - * extensions to complete any data post processing as well as final UTF8 - * validation checks for text messages. - * - * @return A code indicating errors, if any - */ - lib::error_code finalize_message() { - std::string & out = m_current_msg->msg_ptr->get_raw_payload(); - - // if the frame is compressed, append the compression - // trailer and flush the compression buffer. - if (m_permessage_deflate.is_enabled() - && m_current_msg->msg_ptr->get_compressed()) - { - uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff}; - - // Decompress current buffer into the message buffer - lib::error_code ec; - ec = m_permessage_deflate.decompress(trailer,4,out); - if (ec) { - return ec; - } - } - - // ensure that text messages end on a valid UTF8 code point - if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) { - if (!m_current_msg->validator.complete()) { - return make_error_code(error::invalid_utf8); - } - } - - m_state = READY; - - return lib::error_code(); - } - - void reset_headers() { - m_state = HEADER_BASIC; - m_bytes_needed = frame::BASIC_HEADER_LENGTH; - - m_basic_header.b0 = 0x00; - m_basic_header.b1 = 0x00; - - std::fill_n( - m_extended_header.bytes, - frame::MAX_EXTENDED_HEADER_LENGTH, - 0x00 - ); - } - - /// Test whether or not the processor has a message ready - bool ready() const { - return (m_state == READY); - } - - message_ptr get_message() { - if (!ready()) { - return message_ptr(); - } - message_ptr ret = m_current_msg->msg_ptr; - m_current_msg->msg_ptr.reset(); - - if (frame::opcode::is_control(ret->get_opcode())) { - m_control_msg.msg_ptr.reset(); - } else { - m_data_msg.msg_ptr.reset(); - } - - this->reset_headers(); - - return ret; - } - - /// Test whether or not the processor is in a fatal error state. - bool get_error() const { - return m_state == FATAL_ERROR; - } - - size_t get_bytes_needed() const { - return m_bytes_needed; - } - - /// Prepare a user 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 - * - * TODO: tests - * - * @param in An unprepared message to prepare - * @param out A message to be overwritten with the prepared message - * @return error code - */ - virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) - { - if (!in || !out) { - return make_error_code(error::invalid_arguments); - } - - frame::opcode::value op = in->get_opcode(); - - // validate opcode: only regular data frames - if (frame::opcode::is_control(op)) { - 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 (op == frame::opcode::TEXT && !utf8_validator::validate(i)) { - return make_error_code(error::invalid_payload); - } - - frame::masking_key_type key; - bool masked = !base::m_server; - bool compressed = m_permessage_deflate.is_enabled() - && in->get_compressed(); - bool fin = in->get_fin(); - - if (masked) { - // Generate masking key. - key.i = m_rng(); - } else { - key.i = 0; - } - - // prepare payload - if (compressed) { - // compress and store in o after header. - m_permessage_deflate.compress(i,o); - - if (o.size() < 4) { - return make_error_code(error::general); - } - - // Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the - // wire - o.resize(o.size()-4); - - // mask in place if necessary - if (masked) { - this->masked_copy(o,o,key); - } - } else { - // no compression, just copy data into the output buffer - o.resize(i.size()); - - // if we are masked, have the masking function write to the output - // buffer directly to avoid another copy. If not masked, copy - // directly without masking. - if (masked) { - this->masked_copy(i,o,key); - } else { - std::copy(i.begin(),i.end(),o.begin()); - } - } - - // generate header - frame::basic_header h(op,o.size(),fin,masked,compressed); - - if (masked) { - frame::extended_header e(o.size(),key.i); - out->set_header(frame::prepare_header(h,e)); - } else { - frame::extended_header e(o.size()); - out->set_header(frame::prepare_header(h,e)); - } - - out->set_prepared(true); - out->set_opcode(op); - - return lib::error_code(); - } - - /// Get URI - lib::error_code prepare_ping(std::string const & in, message_ptr out) const { - return this->prepare_control(frame::opcode::PING,in,out); - } - - lib::error_code prepare_pong(std::string const & in, message_ptr out) const { - return this->prepare_control(frame::opcode::PONG,in,out); - } - - virtual lib::error_code prepare_close(close::status::value code, - std::string const & reason, message_ptr out) const - { - if (close::status::reserved(code)) { - return make_error_code(error::reserved_close_code); - } - - if (close::status::invalid(code) && code != close::status::no_status) { - return make_error_code(error::invalid_close_code); - } - - if (code == close::status::no_status && reason.size() > 0) { - return make_error_code(error::reason_requires_code); - } - - if (reason.size() > frame:: limits::payload_size_basic-2) { - return make_error_code(error::control_too_big); - } - - std::string payload; - - if (code != close::status::no_status) { - close::code_converter val; - val.i = htons(code); - - payload.resize(reason.size()+2); - - payload[0] = val.c[0]; - payload[1] = val.c[1]; - - std::copy(reason.begin(),reason.end(),payload.begin()+2); - } - - return this->prepare_control(frame::opcode::CLOSE,payload,out); - } -protected: - /// Convert a client handshake key into a server response key in place - lib::error_code process_handshake_key(std::string & key) const { - key.append(constants::handshake_guid); - - unsigned char message_digest[20]; - sha1::calc(key.c_str(),key.length(),message_digest); - key = base64_encode(message_digest,20); - - return lib::error_code(); - } - - /// Reads bytes from buf into m_basic_header - size_t copy_basic_header_bytes(uint8_t const * buf, size_t len) { - if (len == 0 || m_bytes_needed == 0) { - return 0; - } - - if (len > 1) { - // have at least two bytes - if (m_bytes_needed == 2) { - m_basic_header.b0 = buf[0]; - m_basic_header.b1 = buf[1]; - m_bytes_needed -= 2; - return 2; - } else { - m_basic_header.b1 = buf[0]; - m_bytes_needed--; - return 1; - } - } else { - // have exactly one byte - if (m_bytes_needed == 2) { - m_basic_header.b0 = buf[0]; - m_bytes_needed--; - return 1; - } else { - m_basic_header.b1 = buf[0]; - m_bytes_needed--; - return 1; - } - } - } - - /// Reads bytes from buf into m_extended_header - size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) { - size_t bytes_to_read = (std::min)(m_bytes_needed,len); - - std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor); - m_cursor += bytes_to_read; - m_bytes_needed -= bytes_to_read; - - return bytes_to_read; - } - - /// Reads bytes from buf into message payload - /** - * This function performs unmasking and uncompression, validates the - * decoded bytes, and writes them to the appropriate message buffer. - * - * This member function will use the input buffer as stratch space for its - * work. The raw input bytes will not be preserved. This applies only to the - * bytes actually needed. At most min(m_bytes_needed,len) will be processed. - * - * @param buf Input/working buffer - * @param len Length of buf - * @return Number of bytes processed or zero in case of an error - */ - size_t process_payload_bytes(uint8_t * buf, size_t len, lib::error_code& ec) - { - // unmask if masked - if (frame::get_masked(m_basic_header)) { - m_current_msg->prepared_key = frame::byte_mask_circ( - buf, len, m_current_msg->prepared_key); - // TODO: SIMD masking - } - - std::string & out = m_current_msg->msg_ptr->get_raw_payload(); - size_t offset = out.size(); - - // decompress message if needed. - if (m_permessage_deflate.is_enabled() - && m_current_msg->msg_ptr->get_compressed()) - { - // Decompress current buffer into the message buffer - ec = m_permessage_deflate.decompress(buf,len,out); - if (ec) { - return 0; - } - } else { - // No compression, straight copy - out.append(reinterpret_cast(buf),len); - } - - // validate unmasked, decompressed values - if (m_current_msg->msg_ptr->get_opcode() == frame::opcode::TEXT) { - if (!m_current_msg->validator.decode(out.begin()+offset,out.end())) { - ec = make_error_code(error::invalid_utf8); - return 0; - } - } - - m_bytes_needed -= len; - - return len; - } - - /// Validate an incoming basic header - /** - * Validates an incoming hybi13 basic header. - * - * @param h The basic header to validate - * @param is_server Whether or not the endpoint that received this frame - * is a server. - * @param new_msg Whether or not this is the first frame of the message - * @return 0 on success or a non-zero error code on failure - */ - lib::error_code validate_incoming_basic_header(frame::basic_header const & h, - bool is_server, bool new_msg) const - { - frame::opcode::value op = frame::get_opcode(h); - - // Check control frame size limit - if (frame::opcode::is_control(op) && - frame::get_basic_size(h) > frame::limits::payload_size_basic) - { - return make_error_code(error::control_too_big); - } - - // Check that RSV bits are clear - // The only RSV bits allowed are rsv1 if the permessage_compress - // extension is enabled for this connection and the message is not - // a control message. - // - // TODO: unit tests for this - if (frame::get_rsv1(h) && (!m_permessage_deflate.is_enabled() - || frame::opcode::is_control(op))) - { - return make_error_code(error::invalid_rsv_bit); - } - - if (frame::get_rsv2(h) || frame::get_rsv3(h)) { - return make_error_code(error::invalid_rsv_bit); - } - - // Check for reserved opcodes - if (frame::opcode::reserved(op)) { - return make_error_code(error::invalid_opcode); - } - - // Check for invalid opcodes - // TODO: unit tests for this? - if (frame::opcode::invalid(op)) { - return make_error_code(error::invalid_opcode); - } - - // Check for fragmented control message - if (frame::opcode::is_control(op) && !frame::get_fin(h)) { - return make_error_code(error::fragmented_control); - } - - // Check for continuation without an active message - if (new_msg && op == frame::opcode::CONTINUATION) { - return make_error_code(error::invalid_continuation); - } - - // Check for new data frame when expecting continuation - if (!new_msg && !frame::opcode::is_control(op) && - op != frame::opcode::CONTINUATION) - { - return make_error_code(error::invalid_continuation); - } - - // Servers should reject any unmasked frames from clients. - // Clients should reject any masked frames from servers. - if (is_server && !frame::get_masked(h)) { - return make_error_code(error::masking_required); - } else if (!is_server && frame::get_masked(h)) { - return make_error_code(error::masking_forbidden); - } - - return lib::error_code(); - } - - /// Validate an incoming extended header - /** - * Validates an incoming hybi13 full header. - * - * @todo unit test for the >32 bit frames on 32 bit systems case - * - * @param h The basic header to validate - * @param e The extended header to validate - * @return An error_code, non-zero values indicate why the validation - * failed - */ - lib::error_code validate_incoming_extended_header(frame::basic_header h, - frame::extended_header e) const - { - uint8_t basic_size = frame::get_basic_size(h); - uint64_t payload_size = frame::get_payload_size(h,e); - - // Check for non-minimally encoded payloads - if (basic_size == frame::payload_size_code_16bit && - payload_size <= frame::limits::payload_size_basic) - { - return make_error_code(error::non_minimal_encoding); - } - - if (basic_size == frame::payload_size_code_64bit && - payload_size <= frame::limits::payload_size_extended) - { - return make_error_code(error::non_minimal_encoding); - } - - // Check for >32bit frames on 32 bit systems - if (sizeof(size_t) == 4 && (payload_size >> 32)) { - return make_error_code(error::requires_64bit); - } - - return lib::error_code(); - } - - /// Copy and mask/unmask in one operation - /** - * Reads input from one string and writes unmasked output to another. - * - * @param [in] i The input string. - * @param [out] o The output string. - * @param [in] key The masking key to use for masking/unmasking - */ - void masked_copy (std::string const & i, std::string & o, - frame::masking_key_type key) const - { - frame::byte_mask(i.begin(),i.end(),o.begin(),key); - // TODO: SIMD masking - } - - /// Generic prepare control frame with opcode and payload. - /** - * Internal control frame building method. Handles validation, masking, etc - * - * @param op The control opcode to use - * @param payload The payload to use - * @param out The message buffer to store the prepared frame in - * @return Status code, zero on success, non-zero on error - */ - lib::error_code prepare_control(frame::opcode::value op, - std::string const & payload, message_ptr out) const - { - if (!out) { - return make_error_code(error::invalid_arguments); - } - - if (!frame::opcode::is_control(op)) { - return make_error_code(error::invalid_opcode); - } - - if (payload.size() > frame::limits::payload_size_basic) { - return make_error_code(error::control_too_big); - } - - frame::masking_key_type key; - bool masked = !base::m_server; - - frame::basic_header h(op,payload.size(),true,masked); - - std::string & o = out->get_raw_payload(); - o.resize(payload.size()); - - if (masked) { - // Generate masking key. - key.i = m_rng(); - - frame::extended_header e(payload.size(),key.i); - out->set_header(frame::prepare_header(h,e)); - this->masked_copy(payload,o,key); - } else { - frame::extended_header e(payload.size()); - out->set_header(frame::prepare_header(h,e)); - std::copy(payload.begin(),payload.end(),o.begin()); - } - - out->set_opcode(op); - out->set_prepared(true); - - return lib::error_code(); - } - - enum state { - HEADER_BASIC = 0, - HEADER_EXTENDED = 1, - EXTENSION = 2, - APPLICATION = 3, - READY = 4, - FATAL_ERROR = 5 - }; - - /// This data structure holds data related to processing a message, such as - /// the buffer it is being written to, its masking key, its UTF8 validation - /// state, and sometimes its compression state. - struct msg_metadata { - msg_metadata() {} - msg_metadata(message_ptr m, size_t p) : msg_ptr(m),prepared_key(p) {} - msg_metadata(message_ptr m, frame::masking_key_type p) - : msg_ptr(m) - , prepared_key(prepare_masking_key(p)) {} - - message_ptr msg_ptr; // pointer to the message data buffer - size_t prepared_key; // prepared masking key - utf8_validator::validator validator; // utf8 validation state - }; - - // Basic header of the frame being read - frame::basic_header m_basic_header; - - // Pointer to a manager that can create message buffers for us. - msg_manager_ptr m_msg_manager; - - // Number of bytes needed to complete the current operation - size_t m_bytes_needed; - - // Number of extended header bytes read - size_t m_cursor; - - // Metadata for the current data msg - msg_metadata m_data_msg; - // Metadata for the current control msg - msg_metadata m_control_msg; - - // Pointer to the metadata associated with the frame being read - msg_metadata * m_current_msg; - - // Extended header of current frame - frame::extended_header m_extended_header; - - rng_type & m_rng; - - // Overall state of the processor - state m_state; - - // Extensions - permessage_deflate_type m_permessage_deflate; -}; - -} // namespace processor -} // namespace websocketpp - -#endif //WEBSOCKETPP_PROCESSOR_HYBI13_HPP +/* + * 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_HYBI13_HPP +#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace websocketpp { +namespace processor { + +/// Processor for Hybi version 13 (RFC6455) +template +class hybi13 : public processor { +public: + typedef processor 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 msg_manager_type; + typedef typename msg_manager_type::ptr msg_manager_ptr; + typedef typename config::rng_type rng_type; + + typedef typename config::permessage_deflate_type permessage_deflate_type; + + typedef std::pair err_str_pair; + + explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng) + : processor(secure, p_is_server) + , m_msg_manager(manager) + , m_rng(rng) + { + reset_headers(); + } + + int get_version() const { + return 13; + } + + bool has_permessage_deflate() const { + return m_permessage_deflate.is_implemented(); + } + + err_str_pair negotiate_extensions(request_type const & request) { + return negotiate_extensions_helper(request); + } + + err_str_pair negotiate_extensions(response_type const & response) { + return negotiate_extensions_helper(response); + } + + /// Extension negotiation helper function + /** + * This exists mostly because the code for requests and responses is + * identical and I can't have virtual template methods. + */ + template + err_str_pair negotiate_extensions_helper(header_type const & header) { + err_str_pair ret; + + // Respect blanket disabling of all extensions and don't even parse + // the extension header + if (!config::enable_extensions) { + ret.first = make_error_code(error::extensions_disabled); + return ret; + } + + http::parameter_list p; + + bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p); + + if (error) { + ret.first = make_error_code(error::extension_parse_error); + return ret; + } + + // If there are no extensions parsed then we are done! + if (p.size() == 0) { + return ret; + } + + http::parameter_list::const_iterator it; + + // look through the list of extension requests to find the first + // one that we can accept. + if (m_permessage_deflate.is_implemented()) { + err_str_pair neg_ret; + for (it = p.begin(); it != p.end(); ++it) { + // not a permessage-deflate extension request, ignore + if (it->first != "permessage-deflate") { + continue; + } + + // if we have already successfully negotiated this extension + // then skip any other requests to negotiate the same one + // with different parameters + if (m_permessage_deflate.is_enabled()) { + continue; + } + + // attempt to negotiate this offer + neg_ret = m_permessage_deflate.negotiate(it->second); + + if (neg_ret.first) { + // negotiation offer failed. Do nothing. We will continue + // searching for a permessage-deflate config that succeeds + continue; + } + + // Negotiation tentatively succeeded + + // Actually try to initialize the extension before we + // deem negotiation complete + lib::error_code ec = m_permessage_deflate.init(base::m_server); + + if (ec) { + // Negotiation succeeded but initialization failed this is + // an error that should stop negotiation of permessage + // deflate. Return the reason for the init failure + + ret.first = ec; + break; + } else { + // Successfully initialized, push the negotiated response into + // the reply and stop looking for additional permessage-deflate + // extensions + ret.second += neg_ret.second; + break; + } + } + } + + // support for future extensions would go here. Should check the value of + // ret.first before continuing. Might need to consider whether failure of + // negotiation of an earlier extension should stop negotiation of subsequent + // ones + + return ret; + } + + 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-Key").empty()) { + return make_error_code(error::missing_required_header); + } + + return lib::error_code(); + } + + /* TODO: the 'subprotocol' parameter may need to be expanded into a more + * generic struct if other user input parameters to the processed handshake + * are found. + */ + lib::error_code process_handshake(request_type const & request, + std::string const & subprotocol, response_type & response) const + { + std::string server_key = request.get_header("Sec-WebSocket-Key"); + + lib::error_code ec = process_handshake_key(server_key); + + if (ec) { + return ec; + } + + response.replace_header("Sec-WebSocket-Accept",server_key); + response.append_header("Upgrade",constants::upgrade_token); + response.append_header("Connection",constants::connection_token); + + if (!subprotocol.empty()) { + response.replace_header("Sec-WebSocket-Protocol",subprotocol); + } + + return lib::error_code(); + } + + /// Fill in a set of request headers for a client connection request + /** + * @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 & req, uri_ptr + uri, std::vector const & subprotocols) const + { + req.set_method("GET"); + req.set_uri(uri->get_resource()); + req.set_version("HTTP/1.1"); + + req.append_header("Upgrade","websocket"); + req.append_header("Connection","Upgrade"); + req.replace_header("Sec-WebSocket-Version","13"); + req.replace_header("Host",uri->get_host_port()); + + if (!subprotocols.empty()) { + std::ostringstream result; + std::vector::const_iterator it = subprotocols.begin(); + result << *it++; + while (it != subprotocols.end()) { + result << ", " << *it++; + } + + req.replace_header("Sec-WebSocket-Protocol",result.str()); + } + + // Generate handshake key + frame::uint32_converter conv; + unsigned char raw_key[16]; + + for (int i = 0; i < 4; i++) { + conv.i = m_rng(); + std::copy(conv.c,conv.c+4,&raw_key[i*4]); + } + + req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16)); + + if (m_permessage_deflate.is_implemented()) { + std::string offer = m_permessage_deflate.generate_offer(); + if (!offer.empty()) { + req.replace_header("Sec-WebSocket-Extensions",offer); + } + } + + return lib::error_code(); + } + + /// 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 + */ + lib::error_code validate_server_handshake_response(request_type const & req, + response_type& res) const + { + // A valid response has an HTTP 101 switching protocols code + if (res.get_status_code() != http::status_code::switching_protocols) { + return error::make_error_code(error::invalid_http_status); + } + + // And the upgrade token in an upgrade header + std::string const & upgrade_header = res.get_header("Upgrade"); + if (utility::ci_find_substr(upgrade_header, constants::upgrade_token, + sizeof(constants::upgrade_token)-1) == upgrade_header.end()) + { + return error::make_error_code(error::missing_required_header); + } + + // And the websocket token in the connection header + std::string const & con_header = res.get_header("Connection"); + if (utility::ci_find_substr(con_header, constants::connection_token, + sizeof(constants::connection_token)-1) == con_header.end()) + { + return error::make_error_code(error::missing_required_header); + } + + // And has a valid Sec-WebSocket-Accept value + std::string key = req.get_header("Sec-WebSocket-Key"); + lib::error_code ec = process_handshake_key(key); + + if (ec || key != res.get_header("Sec-WebSocket-Accept")) { + return error::make_error_code(error::missing_required_header); + } + + // check extensions + + return lib::error_code(); + } + + std::string get_raw(response_type const & res) const { + return res.raw(); + } + + std::string const & get_origin(request_type const & r) const { + return r.get_header("Origin"); + } + + lib::error_code extract_subprotocols(request_type const & req, + std::vector & 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 { + return get_uri_from_host(request,(base::m_secure ? "wss" : "ws")); + } + + /// Process new websocket connection bytes + /** + * + * Hybi 13 data streams represent a series of variable length frames. Each + * frame is made up of a series of fixed length fields. The lengths of later + * fields are contained in earlier fields. The first field length is fixed + * by the spec. + * + * This processor represents a state machine that keeps track of what field + * is presently being read and how many more bytes are needed to complete it + * + * + * + * + * Read two header bytes + * Extract full frame length. + * Read extra header bytes + * Validate frame header (including extension validate) + * Read extension data into extension message state object + * Read payload data into payload + * + * @param buf Input buffer + * + * @param len Length of input buffer + * + * @return Number of bytes processed or zero on error + */ + size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) { + size_t p = 0; + + ec = lib::error_code(); + + //std::cout << "consume: " << utility::to_hex(buf,len) << std::endl; + + // Loop while we don't have a message ready and we still have bytes + // left to process. + while (m_state != READY && m_state != FATAL_ERROR && + (p < len || m_bytes_needed == 0)) + { + if (m_state == HEADER_BASIC) { + p += this->copy_basic_header_bytes(buf+p,len-p); + + if (m_bytes_needed > 0) { + continue; + } + + ec = this->validate_incoming_basic_header( + m_basic_header, base::m_server, !m_data_msg.msg_ptr + ); + if (ec) {break;} + + // extract full header size and adjust consume state accordingly + m_state = HEADER_EXTENDED; + m_cursor = 0; + m_bytes_needed = frame::get_header_len(m_basic_header) - + frame::BASIC_HEADER_LENGTH; + } else if (m_state == HEADER_EXTENDED) { + p += this->copy_extended_header_bytes(buf+p,len-p); + + if (m_bytes_needed > 0) { + continue; + } + + ec = validate_incoming_extended_header(m_basic_header,m_extended_header); + if (ec){break;} + + m_state = APPLICATION; + m_bytes_needed = static_cast(get_payload_size(m_basic_header,m_extended_header)); + + // check if this frame is the start of a new message and set up + // the appropriate message metadata. + frame::opcode::value op = frame::get_opcode(m_basic_header); + + // TODO: get_message failure conditions + + if (frame::opcode::is_control(op)) { + m_control_msg = msg_metadata( + m_msg_manager->get_message(op,m_bytes_needed), + frame::get_masking_key(m_basic_header,m_extended_header) + ); + + m_current_msg = &m_control_msg; + } else { + if (!m_data_msg.msg_ptr) { + if (m_bytes_needed > base::m_max_message_size) { + ec = make_error_code(error::message_too_big); + break; + } + + m_data_msg = msg_metadata( + m_msg_manager->get_message(op,m_bytes_needed), + frame::get_masking_key(m_basic_header,m_extended_header) + ); + + if (m_permessage_deflate.is_enabled()) { + m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header)); + } + } else { + // Fetch the underlying payload buffer from the data message we + // are writing into. + std::string & out = m_data_msg.msg_ptr->get_raw_payload(); + + if (out.size() + m_bytes_needed > base::m_max_message_size) { + ec = make_error_code(error::message_too_big); + break; + } + + // Each frame starts a new masking key. All other state + // remains between frames. + m_data_msg.prepared_key = prepare_masking_key( + frame::get_masking_key( + m_basic_header, + m_extended_header + ) + ); + + out.reserve(out.size() + m_bytes_needed); + } + m_current_msg = &m_data_msg; + } + } else if (m_state == EXTENSION) { + m_state = APPLICATION; + } else if (m_state == APPLICATION) { + size_t bytes_to_process = (std::min)(m_bytes_needed,len-p); + + if (bytes_to_process > 0) { + p += this->process_payload_bytes(buf+p,bytes_to_process,ec); + + if (ec) {break;} + } + + if (m_bytes_needed > 0) { + continue; + } + + // If this was the last frame in the message set the ready flag. + // Otherwise, reset processor state to read additional frames. + if (frame::get_fin(m_basic_header)) { + ec = finalize_message(); + if (ec) { + break; + } + } else { + this->reset_headers(); + } + } else { + // shouldn't be here + ec = make_error_code(error::general); + return 0; + } + } + + return p; + } + + /// Perform any finalization actions on an incoming message + /** + * Called after the full message is received. Provides the opportunity for + * extensions to complete any data post processing as well as final UTF8 + * validation checks for text messages. + * + * @return A code indicating errors, if any + */ + lib::error_code finalize_message() { + std::string & out = m_current_msg->msg_ptr->get_raw_payload(); + + // if the frame is compressed, append the compression + // trailer and flush the compression buffer. + if (m_permessage_deflate.is_enabled() + && m_current_msg->msg_ptr->get_compressed()) + { + uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff}; + + // Decompress current buffer into the message buffer + lib::error_code ec; + ec = m_permessage_deflate.decompress(trailer,4,out); + if (ec) { + return ec; + } + } + + // ensure that text messages end on a valid UTF8 code point + if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) { + if (!m_current_msg->validator.complete()) { + return make_error_code(error::invalid_utf8); + } + } + + m_state = READY; + + return lib::error_code(); + } + + void reset_headers() { + m_state = HEADER_BASIC; + m_bytes_needed = frame::BASIC_HEADER_LENGTH; + + m_basic_header.b0 = 0x00; + m_basic_header.b1 = 0x00; + + std::fill_n( + m_extended_header.bytes, + frame::MAX_EXTENDED_HEADER_LENGTH, + 0x00 + ); + } + + /// Test whether or not the processor has a message ready + bool ready() const { + return (m_state == READY); + } + + message_ptr get_message() { + if (!ready()) { + return message_ptr(); + } + message_ptr ret = m_current_msg->msg_ptr; + m_current_msg->msg_ptr.reset(); + + if (frame::opcode::is_control(ret->get_opcode())) { + m_control_msg.msg_ptr.reset(); + } else { + m_data_msg.msg_ptr.reset(); + } + + this->reset_headers(); + + return ret; + } + + /// Test whether or not the processor is in a fatal error state. + bool get_error() const { + return m_state == FATAL_ERROR; + } + + size_t get_bytes_needed() const { + return m_bytes_needed; + } + + /// Prepare a user 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 + * + * TODO: tests + * + * @param in An unprepared message to prepare + * @param out A message to be overwritten with the prepared message + * @return error code + */ + virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) + { + if (!in || !out) { + return make_error_code(error::invalid_arguments); + } + + frame::opcode::value op = in->get_opcode(); + + // validate opcode: only regular data frames + if (frame::opcode::is_control(op)) { + 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 (op == frame::opcode::TEXT && !utf8_validator::validate(i)) { + return make_error_code(error::invalid_payload); + } + + frame::masking_key_type key; + bool masked = !base::m_server; + bool compressed = m_permessage_deflate.is_enabled() + && in->get_compressed(); + bool fin = in->get_fin(); + + if (masked) { + // Generate masking key. + key.i = m_rng(); + } else { + key.i = 0; + } + + // prepare payload + if (compressed) { + // compress and store in o after header. + m_permessage_deflate.compress(i,o); + + if (o.size() < 4) { + return make_error_code(error::general); + } + + // Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the + // wire + o.resize(o.size()-4); + + // mask in place if necessary + if (masked) { + this->masked_copy(o,o,key); + } + } else { + // no compression, just copy data into the output buffer + o.resize(i.size()); + + // if we are masked, have the masking function write to the output + // buffer directly to avoid another copy. If not masked, copy + // directly without masking. + if (masked) { + this->masked_copy(i,o,key); + } else { + std::copy(i.begin(),i.end(),o.begin()); + } + } + + // generate header + frame::basic_header h(op,o.size(),fin,masked,compressed); + + if (masked) { + frame::extended_header e(o.size(),key.i); + out->set_header(frame::prepare_header(h,e)); + } else { + frame::extended_header e(o.size()); + out->set_header(frame::prepare_header(h,e)); + } + + out->set_prepared(true); + out->set_opcode(op); + + return lib::error_code(); + } + + /// Get URI + lib::error_code prepare_ping(std::string const & in, message_ptr out) const { + return this->prepare_control(frame::opcode::PING,in,out); + } + + lib::error_code prepare_pong(std::string const & in, message_ptr out) const { + return this->prepare_control(frame::opcode::PONG,in,out); + } + + virtual lib::error_code prepare_close(close::status::value code, + std::string const & reason, message_ptr out) const + { + if (close::status::reserved(code)) { + return make_error_code(error::reserved_close_code); + } + + if (close::status::invalid(code) && code != close::status::no_status) { + return make_error_code(error::invalid_close_code); + } + + if (code == close::status::no_status && reason.size() > 0) { + return make_error_code(error::reason_requires_code); + } + + if (reason.size() > frame:: limits::payload_size_basic-2) { + return make_error_code(error::control_too_big); + } + + std::string payload; + + if (code != close::status::no_status) { + close::code_converter val; + val.i = htons(code); + + payload.resize(reason.size()+2); + + payload[0] = val.c[0]; + payload[1] = val.c[1]; + + std::copy(reason.begin(),reason.end(),payload.begin()+2); + } + + return this->prepare_control(frame::opcode::CLOSE,payload,out); + } +protected: + /// Convert a client handshake key into a server response key in place + lib::error_code process_handshake_key(std::string & key) const { + key.append(constants::handshake_guid); + + unsigned char message_digest[20]; + sha1::calc(key.c_str(),key.length(),message_digest); + key = base64_encode(message_digest,20); + + return lib::error_code(); + } + + /// Reads bytes from buf into m_basic_header + size_t copy_basic_header_bytes(uint8_t const * buf, size_t len) { + if (len == 0 || m_bytes_needed == 0) { + return 0; + } + + if (len > 1) { + // have at least two bytes + if (m_bytes_needed == 2) { + m_basic_header.b0 = buf[0]; + m_basic_header.b1 = buf[1]; + m_bytes_needed -= 2; + return 2; + } else { + m_basic_header.b1 = buf[0]; + m_bytes_needed--; + return 1; + } + } else { + // have exactly one byte + if (m_bytes_needed == 2) { + m_basic_header.b0 = buf[0]; + m_bytes_needed--; + return 1; + } else { + m_basic_header.b1 = buf[0]; + m_bytes_needed--; + return 1; + } + } + } + + /// Reads bytes from buf into m_extended_header + size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) { + size_t bytes_to_read = (std::min)(m_bytes_needed,len); + + std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor); + m_cursor += bytes_to_read; + m_bytes_needed -= bytes_to_read; + + return bytes_to_read; + } + + /// Reads bytes from buf into message payload + /** + * This function performs unmasking and uncompression, validates the + * decoded bytes, and writes them to the appropriate message buffer. + * + * This member function will use the input buffer as stratch space for its + * work. The raw input bytes will not be preserved. This applies only to the + * bytes actually needed. At most min(m_bytes_needed,len) will be processed. + * + * @param buf Input/working buffer + * @param len Length of buf + * @return Number of bytes processed or zero in case of an error + */ + size_t process_payload_bytes(uint8_t * buf, size_t len, lib::error_code& ec) + { + // unmask if masked + if (frame::get_masked(m_basic_header)) { + m_current_msg->prepared_key = frame::byte_mask_circ( + buf, len, m_current_msg->prepared_key); + // TODO: SIMD masking + } + + std::string & out = m_current_msg->msg_ptr->get_raw_payload(); + size_t offset = out.size(); + + // decompress message if needed. + if (m_permessage_deflate.is_enabled() + && m_current_msg->msg_ptr->get_compressed()) + { + // Decompress current buffer into the message buffer + ec = m_permessage_deflate.decompress(buf,len,out); + if (ec) { + return 0; + } + } else { + // No compression, straight copy + out.append(reinterpret_cast(buf),len); + } + + // validate unmasked, decompressed values + if (m_current_msg->msg_ptr->get_opcode() == frame::opcode::TEXT) { + if (!m_current_msg->validator.decode(out.begin()+offset,out.end())) { + ec = make_error_code(error::invalid_utf8); + return 0; + } + } + + m_bytes_needed -= len; + + return len; + } + + /// Validate an incoming basic header + /** + * Validates an incoming hybi13 basic header. + * + * @param h The basic header to validate + * @param is_server Whether or not the endpoint that received this frame + * is a server. + * @param new_msg Whether or not this is the first frame of the message + * @return 0 on success or a non-zero error code on failure + */ + lib::error_code validate_incoming_basic_header(frame::basic_header const & h, + bool is_server, bool new_msg) const + { + frame::opcode::value op = frame::get_opcode(h); + + // Check control frame size limit + if (frame::opcode::is_control(op) && + frame::get_basic_size(h) > frame::limits::payload_size_basic) + { + return make_error_code(error::control_too_big); + } + + // Check that RSV bits are clear + // The only RSV bits allowed are rsv1 if the permessage_compress + // extension is enabled for this connection and the message is not + // a control message. + // + // TODO: unit tests for this + if (frame::get_rsv1(h) && (!m_permessage_deflate.is_enabled() + || frame::opcode::is_control(op))) + { + return make_error_code(error::invalid_rsv_bit); + } + + if (frame::get_rsv2(h) || frame::get_rsv3(h)) { + return make_error_code(error::invalid_rsv_bit); + } + + // Check for reserved opcodes + if (frame::opcode::reserved(op)) { + return make_error_code(error::invalid_opcode); + } + + // Check for invalid opcodes + // TODO: unit tests for this? + if (frame::opcode::invalid(op)) { + return make_error_code(error::invalid_opcode); + } + + // Check for fragmented control message + if (frame::opcode::is_control(op) && !frame::get_fin(h)) { + return make_error_code(error::fragmented_control); + } + + // Check for continuation without an active message + if (new_msg && op == frame::opcode::CONTINUATION) { + return make_error_code(error::invalid_continuation); + } + + // Check for new data frame when expecting continuation + if (!new_msg && !frame::opcode::is_control(op) && + op != frame::opcode::CONTINUATION) + { + return make_error_code(error::invalid_continuation); + } + + // Servers should reject any unmasked frames from clients. + // Clients should reject any masked frames from servers. + if (is_server && !frame::get_masked(h)) { + return make_error_code(error::masking_required); + } else if (!is_server && frame::get_masked(h)) { + return make_error_code(error::masking_forbidden); + } + + return lib::error_code(); + } + + /// Validate an incoming extended header + /** + * Validates an incoming hybi13 full header. + * + * @todo unit test for the >32 bit frames on 32 bit systems case + * + * @param h The basic header to validate + * @param e The extended header to validate + * @return An error_code, non-zero values indicate why the validation + * failed + */ + lib::error_code validate_incoming_extended_header(frame::basic_header h, + frame::extended_header e) const + { + uint8_t basic_size = frame::get_basic_size(h); + uint64_t payload_size = frame::get_payload_size(h,e); + + // Check for non-minimally encoded payloads + if (basic_size == frame::payload_size_code_16bit && + payload_size <= frame::limits::payload_size_basic) + { + return make_error_code(error::non_minimal_encoding); + } + + if (basic_size == frame::payload_size_code_64bit && + payload_size <= frame::limits::payload_size_extended) + { + return make_error_code(error::non_minimal_encoding); + } + + // Check for >32bit frames on 32 bit systems + if (sizeof(size_t) == 4 && (payload_size >> 32)) { + return make_error_code(error::requires_64bit); + } + + return lib::error_code(); + } + + /// Copy and mask/unmask in one operation + /** + * Reads input from one string and writes unmasked output to another. + * + * @param [in] i The input string. + * @param [out] o The output string. + * @param [in] key The masking key to use for masking/unmasking + */ + void masked_copy (std::string const & i, std::string & o, + frame::masking_key_type key) const + { + frame::byte_mask(i.begin(),i.end(),o.begin(),key); + // TODO: SIMD masking + } + + /// Generic prepare control frame with opcode and payload. + /** + * Internal control frame building method. Handles validation, masking, etc + * + * @param op The control opcode to use + * @param payload The payload to use + * @param out The message buffer to store the prepared frame in + * @return Status code, zero on success, non-zero on error + */ + lib::error_code prepare_control(frame::opcode::value op, + std::string const & payload, message_ptr out) const + { + if (!out) { + return make_error_code(error::invalid_arguments); + } + + if (!frame::opcode::is_control(op)) { + return make_error_code(error::invalid_opcode); + } + + if (payload.size() > frame::limits::payload_size_basic) { + return make_error_code(error::control_too_big); + } + + frame::masking_key_type key; + bool masked = !base::m_server; + + frame::basic_header h(op,payload.size(),true,masked); + + std::string & o = out->get_raw_payload(); + o.resize(payload.size()); + + if (masked) { + // Generate masking key. + key.i = m_rng(); + + frame::extended_header e(payload.size(),key.i); + out->set_header(frame::prepare_header(h,e)); + this->masked_copy(payload,o,key); + } else { + frame::extended_header e(payload.size()); + out->set_header(frame::prepare_header(h,e)); + std::copy(payload.begin(),payload.end(),o.begin()); + } + + out->set_opcode(op); + out->set_prepared(true); + + return lib::error_code(); + } + + enum state { + HEADER_BASIC = 0, + HEADER_EXTENDED = 1, + EXTENSION = 2, + APPLICATION = 3, + READY = 4, + FATAL_ERROR = 5 + }; + + /// This data structure holds data related to processing a message, such as + /// the buffer it is being written to, its masking key, its UTF8 validation + /// state, and sometimes its compression state. + struct msg_metadata { + msg_metadata() {} + msg_metadata(message_ptr m, size_t p) : msg_ptr(m),prepared_key(p) {} + msg_metadata(message_ptr m, frame::masking_key_type p) + : msg_ptr(m) + , prepared_key(prepare_masking_key(p)) {} + + message_ptr msg_ptr; // pointer to the message data buffer + size_t prepared_key; // prepared masking key + utf8_validator::validator validator; // utf8 validation state + }; + + // Basic header of the frame being read + frame::basic_header m_basic_header; + + // Pointer to a manager that can create message buffers for us. + msg_manager_ptr m_msg_manager; + + // Number of bytes needed to complete the current operation + size_t m_bytes_needed; + + // Number of extended header bytes read + size_t m_cursor; + + // Metadata for the current data msg + msg_metadata m_data_msg; + // Metadata for the current control msg + msg_metadata m_control_msg; + + // Pointer to the metadata associated with the frame being read + msg_metadata * m_current_msg; + + // Extended header of current frame + frame::extended_header m_extended_header; + + rng_type & m_rng; + + // Overall state of the processor + state m_state; + + // Extensions + permessage_deflate_type m_permessage_deflate; +}; + +} // namespace processor +} // namespace websocketpp + +#endif //WEBSOCKETPP_PROCESSOR_HYBI13_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/processors/processor.hpp b/thirdparty/websocketpp/include/websocketpp/processors/processor.hpp index ee782a5..5131cc4 100644 --- a/thirdparty/websocketpp/include/websocketpp/processors/processor.hpp +++ b/thirdparty/websocketpp/include/websocketpp/processors/processor.hpp @@ -1,407 +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 -#include - -#include -#include -#include - -#include -#include -#include -#include - -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 -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 -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 -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(scheme, h, request.get_uri()); - } else { - return lib::make_shared(scheme, - h.substr(0,last_colon), - h.substr(last_colon+1), - request.get_uri()); - } -} - -/// WebSocket protocol processor abstract base class -template -class processor { -public: - typedef processor 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 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 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 & 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 +/* + * 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 +#include + +#include +#include +#include + +#include +#include +#include +#include + +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 +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 +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 +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(scheme, h, request.get_uri()); + } else { + return lib::make_shared(scheme, + h.substr(0,last_colon), + h.substr(last_colon+1), + request.get_uri()); + } +} + +/// WebSocket protocol processor abstract base class +template +class processor { +public: + typedef processor 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 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 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 & 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 diff --git a/thirdparty/websocketpp/include/websocketpp/random/none.hpp b/thirdparty/websocketpp/include/websocketpp/random/none.hpp index ecb2d0f..2163e6f 100644 --- a/thirdparty/websocketpp/include/websocketpp/random/none.hpp +++ b/thirdparty/websocketpp/include/websocketpp/random/none.hpp @@ -1,60 +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 -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 +/* + * 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 +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 diff --git a/thirdparty/websocketpp/include/websocketpp/random/random_device.hpp b/thirdparty/websocketpp/include/websocketpp/random/random_device.hpp index 65bbe60..91e7dd1 100644 --- a/thirdparty/websocketpp/include/websocketpp/random/random_device.hpp +++ b/thirdparty/websocketpp/include/websocketpp/random/random_device.hpp @@ -1,80 +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 - -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 -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 m_dis; - - mutex_type m_lock; -}; - -} // namespace random_device -} // namespace random -} // namespace websocketpp - -#endif //WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP +/* + * 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 + +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 +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 m_dis; + + mutex_type m_lock; +}; + +} // namespace random_device +} // namespace random +} // namespace websocketpp + +#endif //WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/roles/client_endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/roles/client_endpoint.hpp index 734678d..4d0c433 100644 --- a/thirdparty/websocketpp/include/websocketpp/roles/client_endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/roles/client_endpoint.hpp @@ -1,173 +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 -#include - -#include - -#include - -#include - -namespace websocketpp { - -/// Client endpoint role based on the given config -/** - * - */ -template -class client : public endpoint,config> { -public: - /// Type of this endpoint - typedef client 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 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 endpoint_type; - - friend class connection; - - 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(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(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 +/* + * 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 +#include + +#include + +#include + +#include + +namespace websocketpp { + +/// Client endpoint role based on the given config +/** + * + */ +template +class client : public endpoint,config> { +public: + /// Type of this endpoint + typedef client 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 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 endpoint_type; + + friend class connection; + + 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(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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/roles/server_endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/roles/server_endpoint.hpp index 9a71cde..9cc652f 100644 --- a/thirdparty/websocketpp/include/websocketpp/roles/server_endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/roles/server_endpoint.hpp @@ -1,195 +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 - -#include - -#include - -namespace websocketpp { - -/// Server endpoint role based on the given config -/** - * - */ -template -class server : public endpoint,config> { -public: - /// Type of this endpoint - typedef server 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 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 endpoint_type; - - friend class connection; - - explicit server() : endpoint_type(true) - { - endpoint_type::m_alog->write(log::alevel::devel, "server constructor"); - } - - /// Destructor - ~server() {} - -#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - // no copy constructor because endpoints are not copyable - server(server &) = delete; - - // no copy assignment operator because endpoints are not copyable - server & operator=(server const &) = delete; -#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - -#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ - /// Move constructor - server(server && o) : endpoint,config>(std::move(o)) {} - -#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - // no move assignment operator because of const member variables - server & operator=(server &&) = 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(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 +/* + * 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 + +#include + +#include + +namespace websocketpp { + +/// Server endpoint role based on the given config +/** + * + */ +template +class server : public endpoint,config> { +public: + /// Type of this endpoint + typedef server 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 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 endpoint_type; + + friend class connection; + + explicit server() : endpoint_type(true) + { + endpoint_type::m_alog->write(log::alevel::devel, "server constructor"); + } + + /// Destructor + ~server() {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no copy constructor because endpoints are not copyable + server(server &) = delete; + + // no copy assignment operator because endpoints are not copyable + server & operator=(server const &) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Move constructor + server(server && o) : endpoint,config>(std::move(o)) {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no move assignment operator because of const member variables + server & operator=(server &&) = 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(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 diff --git a/thirdparty/websocketpp/include/websocketpp/server.hpp b/thirdparty/websocketpp/include/websocketpp/server.hpp index ce46eaa..342fa8c 100644 --- a/thirdparty/websocketpp/include/websocketpp/server.hpp +++ b/thirdparty/websocketpp/include/websocketpp/server.hpp @@ -1,33 +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 - -#endif //WEBSOCKETPP_SERVER_HPP +/* + * 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 + +#endif //WEBSOCKETPP_SERVER_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/sha1/sha1.hpp b/thirdparty/websocketpp/include/websocketpp/sha1/sha1.hpp index 43a8433..6b48d95 100644 --- a/thirdparty/websocketpp/include/websocketpp/sha1/sha1.hpp +++ b/thirdparty/websocketpp/include/websocketpp/sha1/sha1.hpp @@ -1,189 +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 +/* +***** +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 diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/base.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/base.hpp index d4e5b5d..b945fe1 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/base.hpp @@ -1,232 +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 -#include -#include -#include -#include - -#include - -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(&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::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 -class custom_alloc_handler { -public: - custom_alloc_handler(handler_allocator& a, Handler h) - : allocator_(a), - handler_(h) - {} - - template - void operator()(Arg1 arg1) { - handler_(arg1); - } - - template - void operator()(Arg1 arg1, Arg2 arg2) { - handler_(arg1, arg2); - } - - friend void* asio_handler_allocate(std::size_t size, - custom_alloc_handler * this_handler) - { - return this_handler->allocator_.allocate(size); - } - - friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, - custom_alloc_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 -inline custom_alloc_handler make_custom_alloc_handler( - handler_allocator & a, Handler h) -{ - return custom_alloc_handler(a, h); -} - - - - - - - -// Forward declaration of class endpoint so that it can be friended/referenced -// before being included. -template -class endpoint; - -typedef lib::function async_read_handler; - -typedef lib::function async_write_handler; - -typedef lib::function 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(e), get_category()); -} - -} // namespace error -} // namespace asio -} // namespace transport -} // namespace websocketpp - -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ -#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP +/* + * 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 +#include +#include +#include +#include + +#include + +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(&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::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 +class custom_alloc_handler { +public: + custom_alloc_handler(handler_allocator& a, Handler h) + : allocator_(a), + handler_(h) + {} + + template + void operator()(Arg1 arg1) { + handler_(arg1); + } + + template + void operator()(Arg1 arg1, Arg2 arg2) { + handler_(arg1, arg2); + } + + friend void* asio_handler_allocate(std::size_t size, + custom_alloc_handler * this_handler) + { + return this_handler->allocator_.allocate(size); + } + + friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, + custom_alloc_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 +inline custom_alloc_handler make_custom_alloc_handler( + handler_allocator & a, Handler h) +{ + return custom_alloc_handler(a, h); +} + + + + + + + +// Forward declaration of class endpoint so that it can be friended/referenced +// before being included. +template +class endpoint; + +typedef lib::function async_read_handler; + +typedef lib::function async_write_handler; + +typedef lib::function 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(e), get_category()); +} + +} // namespace error +} // namespace asio +} // namespace transport +} // namespace websocketpp + +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ +#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/connection.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/connection.hpp index e25157e..57dda74 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/connection.hpp @@ -1,1197 +1,1197 @@ -/* - * 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_CON_HPP -#define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP - -#include - -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace websocketpp { -namespace transport { -namespace asio { - -typedef lib::function tcp_init_handler; - -/// Asio based connection transport component -/** - * transport::asio::connection implements a connection transport component using - * Asio that works with the transport::asio::endpoint endpoint transport - * component. - */ -template -class connection : public config::socket_type::socket_con_type { -public: - /// Type of this connection transport component - typedef connection type; - /// Type of a shared pointer to this connection transport component - typedef lib::shared_ptr ptr; - - /// Type of the socket connection component - typedef typename config::socket_type::socket_con_type socket_con_type; - /// Type of a shared pointer to the socket connection component - typedef typename socket_con_type::ptr socket_con_ptr; - /// Type of this transport's access logging policy - typedef typename config::alog_type alog_type; - /// Type of this transport's error logging policy - typedef typename config::elog_type elog_type; - - typedef typename config::request_type request_type; - typedef typename request_type::ptr request_ptr; - typedef typename config::response_type response_type; - typedef typename response_type::ptr response_ptr; - - /// Type of a pointer to the Asio io_service being used - typedef lib::asio::io_service * io_service_ptr; - /// Type of a pointer to the Asio io_service::strand being used - typedef lib::shared_ptr strand_ptr; - /// Type of a pointer to the Asio timer class - typedef lib::shared_ptr timer_ptr; - - // connection is friends with its associated endpoint to allow the endpoint - // to call private/protected utility methods that we don't want to expose - // to the public api. - friend class endpoint; - - // generate and manage our own io_service - explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) - : m_is_server(is_server) - , m_alog(alog) - , m_elog(elog) - { - m_alog->write(log::alevel::devel,"asio con transport constructor"); - } - - /// Get a shared pointer to this component - ptr get_shared() { - return lib::static_pointer_cast(socket_con_type::get_shared()); - } - - bool is_secure() const { - return socket_con_type::is_secure(); - } - - /// Set uri hook - /** - * Called by the endpoint as a connection is being established to provide - * the uri being connected to to the transport layer. - * - * This transport policy doesn't use the uri except to forward it to the - * socket layer. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr u) { - socket_con_type::set_uri(u); - } - - /// Sets the tcp pre init handler - /** - * The tcp pre init handler is called after the raw tcp connection has been - * established but before any additional wrappers (proxy connects, TLS - * handshakes, etc) have been performed. - * - * @since 0.3.0 - * - * @param h The handler to call on tcp pre init. - */ - void set_tcp_pre_init_handler(tcp_init_handler h) { - m_tcp_pre_init_handler = h; - } - - /// Sets the tcp pre init handler (deprecated) - /** - * The tcp pre init handler is called after the raw tcp connection has been - * established but before any additional wrappers (proxy connects, TLS - * handshakes, etc) have been performed. - * - * @deprecated Use set_tcp_pre_init_handler instead - * - * @param h The handler to call on tcp pre init. - */ - void set_tcp_init_handler(tcp_init_handler h) { - set_tcp_pre_init_handler(h); - } - - /// Sets the tcp post init handler - /** - * The tcp post init handler is called after the tcp connection has been - * established and all additional wrappers (proxy connects, TLS handshakes, - * etc have been performed. This is fired before any bytes are read or any - * WebSocket specific handshake logic has been performed. - * - * @since 0.3.0 - * - * @param h The handler to call on tcp post init. - */ - void set_tcp_post_init_handler(tcp_init_handler h) { - m_tcp_post_init_handler = h; - } - - /// Set the proxy to connect through (exception free) - /** - * The URI passed should be a complete URI including scheme. For example: - * http://proxy.example.com:8080/ - * - * The proxy must be set up as an explicit (CONNECT) proxy allowed to - * connect to the port you specify. Traffic to the proxy is not encrypted. - * - * @param uri The full URI of the proxy to connect to. - * - * @param ec A status value - */ - void set_proxy(std::string const & uri, lib::error_code & ec) { - // TODO: return errors for illegal URIs here? - // TODO: should https urls be illegal for the moment? - m_proxy = uri; - m_proxy_data = lib::make_shared(); - ec = lib::error_code(); - } - - /// Set the proxy to connect through (exception) - void set_proxy(std::string const & uri) { - lib::error_code ec; - set_proxy(uri,ec); - if (ec) { throw exception(ec); } - } - - /// Set the basic auth credentials to use (exception free) - /** - * The URI passed should be a complete URI including scheme. For example: - * http://proxy.example.com:8080/ - * - * The proxy must be set up as an explicit proxy - * - * @param username The username to send - * - * @param password The password to send - * - * @param ec A status value - */ - void set_proxy_basic_auth(std::string const & username, std::string const & - password, lib::error_code & ec) - { - if (!m_proxy_data) { - ec = make_error_code(websocketpp::error::invalid_state); - return; - } - - // TODO: username can't contain ':' - std::string val = "Basic "+base64_encode(username + ":" + password); - m_proxy_data->req.replace_header("Proxy-Authorization",val); - ec = lib::error_code(); - } - - /// Set the basic auth credentials to use (exception) - void set_proxy_basic_auth(std::string const & username, std::string const & - password) - { - lib::error_code ec; - set_proxy_basic_auth(username,password,ec); - if (ec) { throw exception(ec); } - } - - /// Set the proxy timeout duration (exception free) - /** - * Duration is in milliseconds. Default value is based on the transport - * config - * - * @param duration The number of milliseconds to wait before aborting the - * proxy connection. - * - * @param ec A status value - */ - void set_proxy_timeout(long duration, lib::error_code & ec) { - if (!m_proxy_data) { - ec = make_error_code(websocketpp::error::invalid_state); - return; - } - - m_proxy_data->timeout_proxy = duration; - ec = lib::error_code(); - } - - /// Set the proxy timeout duration (exception) - void set_proxy_timeout(long duration) { - lib::error_code ec; - set_proxy_timeout(duration,ec); - if (ec) { throw exception(ec); } - } - - std::string const & get_proxy() const { - return m_proxy; - } - - /// Get the remote endpoint address - /** - * The iostream transport has no information about the ultimate remote - * endpoint. It will return the string "iostream transport". To indicate - * this. - * - * TODO: allow user settable remote endpoint addresses if this seems useful - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint() const { - lib::error_code ec; - - std::string ret = socket_con_type::get_remote_endpoint(ec); - - if (ec) { - m_elog->write(log::elevel::info,ret); - return "Unknown"; - } else { - return ret; - } - } - - /// Get the connection handle - connection_hdl get_handle() const { - return m_connection_hdl; - } - - /// Call back a function after a period of time. - /** - * Sets a timer that calls back a function after the specified period of - * milliseconds. Returns a handle that can be used to cancel the timer. - * A cancelled timer will return the error code error::operation_aborted - * A timer that expired will return no error. - * - * @param duration Length of time to wait in milliseconds - * - * @param callback The function to call back when the timer has expired - * - * @return A handle that can be used to cancel the timer if it is no longer - * needed. - */ - timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer( - new lib::asio::steady_timer( - *m_io_service, - lib::asio::milliseconds(duration)) - ); - - if (config::enable_multithreading) { - new_timer->async_wait(m_strand->wrap(lib::bind( - &type::handle_timer, get_shared(), - new_timer, - callback, - lib::placeholders::_1 - ))); - } else { - new_timer->async_wait(lib::bind( - &type::handle_timer, get_shared(), - new_timer, - callback, - lib::placeholders::_1 - )); - } - - return new_timer; - } - - /// Timer callback - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * TODO: candidate for protected status - * - * @param post_timer Pointer to the timer in question - * @param callback The function to call back - * @param ec The status code - */ - void handle_timer(timer_ptr, timer_handler callback, - lib::asio::error_code const & ec) - { - if (ec) { - if (ec == lib::asio::error::operation_aborted) { - callback(make_error_code(transport::error::operation_aborted)); - } else { - log_err(log::elevel::info,"asio handle_timer",ec); - callback(make_error_code(error::pass_through)); - } - } else { - callback(lib::error_code()); - } - } - - /// Get a pointer to this connection's strand - strand_ptr get_strand() { - return m_strand; - } - - /// Get the internal transport error code for a closed/failed connection - /** - * Retrieves a machine readable detailed error code indicating the reason - * that the connection was closed or failed. Valid only after the close or - * fail handler is called. - * - * Primarily used if you are using mismatched asio / system_error - * implementations such as `boost::asio` with `std::system_error`. In these - * cases the transport error type is different than the library error type - * and some WebSocket++ functions that return transport errors via the - * library error code type will be coerced into a catch all `pass_through` - * or `tls_error` error. This method will return the original machine - * readable transport error in the native type. - * - * @since 0.7.0 - * - * @return Error code indicating the reason the connection was closed or - * failed - */ - lib::asio::error_code get_transport_ec() const { - return m_tec; - } - - /// Initialize transport for reading - /** - * init_asio is called once immediately after construction to initialize - * Asio components to the io_service - * - * The transport initialization sequence consists of the following steps: - * - Pre-init: the underlying socket is initialized to the point where - * bytes may be written. No bytes are actually written in this stage - * - Proxy negotiation: if a proxy is set, a request is made to it to start - * a tunnel to the final destination. This stage ends when the proxy is - * ready to forward the - * next byte to the remote endpoint. - * - Post-init: Perform any i/o with the remote endpoint, such as setting up - * tunnels for encryption. This stage ends when the connection is ready to - * read or write the WebSocket handshakes. At this point the original - * callback function is called. - */ -protected: - void init(init_handler callback) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection init"); - } - - // TODO: pre-init timeout. Right now no implemented socket policies - // actually have an asyncronous pre-init - - socket_con_type::pre_init( - lib::bind( - &type::handle_pre_init, - get_shared(), - callback, - lib::placeholders::_1 - ) - ); - } - - /// initialize the proxy buffers and http parsers - /** - * - * @param authority The address of the server we want the proxy to tunnel to - * in the format of a URI authority (host:port) - * - * @return Status code indicating what errors occurred, if any - */ - lib::error_code proxy_init(std::string const & authority) { - if (!m_proxy_data) { - return websocketpp::error::make_error_code( - websocketpp::error::invalid_state); - } - m_proxy_data->req.set_version("HTTP/1.1"); - m_proxy_data->req.set_method("CONNECT"); - - m_proxy_data->req.set_uri(authority); - m_proxy_data->req.replace_header("Host",authority); - - return lib::error_code(); - } - - /// Finish constructing the transport - /** - * init_asio is called once immediately after construction to initialize - * Asio components to the io_service. - * - * @param io_service A pointer to the io_service to register with this - * connection - * - * @return Status code for the success or failure of the initialization - */ - lib::error_code init_asio (io_service_ptr io_service) { - m_io_service = io_service; - - if (config::enable_multithreading) { - m_strand.reset(new lib::asio::io_service::strand(*io_service)); - } - - lib::error_code ec = socket_con_type::init_asio(io_service, m_strand, - m_is_server); - - return ec; - } - - void handle_pre_init(init_handler callback, lib::error_code const & ec) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection handle pre_init"); - } - - if (m_tcp_pre_init_handler) { - m_tcp_pre_init_handler(m_connection_hdl); - } - - if (ec) { - callback(ec); - } - - // If we have a proxy set issue a proxy connect, otherwise skip to - // post_init - if (!m_proxy.empty()) { - proxy_write(callback); - } else { - post_init(callback); - } - } - - void post_init(init_handler callback) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection post_init"); - } - - timer_ptr post_timer; - - if (config::timeout_socket_post_init > 0) { - post_timer = set_timer( - config::timeout_socket_post_init, - lib::bind( - &type::handle_post_init_timeout, - get_shared(), - post_timer, - callback, - lib::placeholders::_1 - ) - ); - } - - socket_con_type::post_init( - lib::bind( - &type::handle_post_init, - get_shared(), - post_timer, - callback, - lib::placeholders::_1 - ) - ); - } - - /// Post init timeout callback - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * @param post_timer Pointer to the timer in question - * @param callback The function to call back - * @param ec The status code - */ - void handle_post_init_timeout(timer_ptr, init_handler callback, - lib::error_code const & ec) - { - lib::error_code ret_ec; - - if (ec) { - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel, - "asio post init timer cancelled"); - return; - } - - log_err(log::elevel::devel,"asio handle_post_init_timeout",ec); - ret_ec = ec; - } else { - if (socket_con_type::get_ec()) { - ret_ec = socket_con_type::get_ec(); - } else { - ret_ec = make_error_code(transport::error::timeout); - } - } - - m_alog->write(log::alevel::devel, "Asio transport post-init timed out"); - cancel_socket_checked(); - callback(ret_ec); - } - - /// Post init timeout callback - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * @param post_timer Pointer to the timer in question - * @param callback The function to call back - * @param ec The status code - */ - void handle_post_init(timer_ptr post_timer, init_handler callback, - lib::error_code const & ec) - { - if (ec == transport::error::operation_aborted || - (post_timer && lib::asio::is_neg(post_timer->expires_from_now()))) - { - m_alog->write(log::alevel::devel,"post_init cancelled"); - return; - } - - if (post_timer) { - post_timer->cancel(); - } - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection handle_post_init"); - } - - if (m_tcp_post_init_handler) { - m_tcp_post_init_handler(m_connection_hdl); - } - - callback(ec); - } - - void proxy_write(init_handler callback) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection proxy_write"); - } - - if (!m_proxy_data) { - m_elog->write(log::elevel::library, - "assertion failed: !m_proxy_data in asio::connection::proxy_write"); - callback(make_error_code(error::general)); - return; - } - - m_proxy_data->write_buf = m_proxy_data->req.raw(); - - m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(), - m_proxy_data->write_buf.size())); - - m_alog->write(log::alevel::devel,m_proxy_data->write_buf); - - // Set a timer so we don't wait forever for the proxy to respond - m_proxy_data->timer = this->set_timer( - m_proxy_data->timeout_proxy, - lib::bind( - &type::handle_proxy_timeout, - get_shared(), - callback, - lib::placeholders::_1 - ) - ); - - // Send proxy request - if (config::enable_multithreading) { - lib::asio::async_write( - socket_con_type::get_next_layer(), - m_bufs, - m_strand->wrap(lib::bind( - &type::handle_proxy_write, get_shared(), - callback, - lib::placeholders::_1 - )) - ); - } else { - lib::asio::async_write( - socket_con_type::get_next_layer(), - m_bufs, - lib::bind( - &type::handle_proxy_write, get_shared(), - callback, - lib::placeholders::_1 - ) - ); - } - } - - void handle_proxy_timeout(init_handler callback, lib::error_code const & ec) - { - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel, - "asio handle_proxy_write timer cancelled"); - return; - } else if (ec) { - log_err(log::elevel::devel,"asio handle_proxy_write",ec); - callback(ec); - } else { - m_alog->write(log::alevel::devel, - "asio handle_proxy_write timer expired"); - cancel_socket_checked(); - callback(make_error_code(transport::error::timeout)); - } - } - - void handle_proxy_write(init_handler callback, - lib::asio::error_code const & ec) - { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel, - "asio connection handle_proxy_write"); - } - - m_bufs.clear(); - - // Timer expired or the operation was aborted for some reason. - // Whatever aborted it will be issuing the callback so we are safe to - // return - if (ec == lib::asio::error::operation_aborted || - lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) - { - m_elog->write(log::elevel::devel,"write operation aborted"); - return; - } - - if (ec) { - log_err(log::elevel::info,"asio handle_proxy_write",ec); - m_proxy_data->timer->cancel(); - callback(make_error_code(error::pass_through)); - return; - } - - proxy_read(callback); - } - - void proxy_read(init_handler callback) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection proxy_read"); - } - - if (!m_proxy_data) { - m_elog->write(log::elevel::library, - "assertion failed: !m_proxy_data in asio::connection::proxy_read"); - m_proxy_data->timer->cancel(); - callback(make_error_code(error::general)); - return; - } - - if (config::enable_multithreading) { - lib::asio::async_read_until( - socket_con_type::get_next_layer(), - m_proxy_data->read_buf, - "\r\n\r\n", - m_strand->wrap(lib::bind( - &type::handle_proxy_read, get_shared(), - callback, - lib::placeholders::_1, lib::placeholders::_2 - )) - ); - } else { - lib::asio::async_read_until( - socket_con_type::get_next_layer(), - m_proxy_data->read_buf, - "\r\n\r\n", - lib::bind( - &type::handle_proxy_read, get_shared(), - callback, - lib::placeholders::_1, lib::placeholders::_2 - ) - ); - } - } - - /// Proxy read callback - /** - * @param init_handler The function to call back - * @param ec The status code - * @param bytes_transferred The number of bytes read - */ - void handle_proxy_read(init_handler callback, - lib::asio::error_code const & ec, size_t) - { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel, - "asio connection handle_proxy_read"); - } - - // Timer expired or the operation was aborted for some reason. - // Whatever aborted it will be issuing the callback so we are safe to - // return - if (ec == lib::asio::error::operation_aborted || - lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) - { - m_elog->write(log::elevel::devel,"read operation aborted"); - return; - } - - // At this point there is no need to wait for the timer anymore - m_proxy_data->timer->cancel(); - - if (ec) { - m_elog->write(log::elevel::info, - "asio handle_proxy_read error: "+ec.message()); - callback(make_error_code(error::pass_through)); - } else { - if (!m_proxy_data) { - m_elog->write(log::elevel::library, - "assertion failed: !m_proxy_data in asio::connection::handle_proxy_read"); - callback(make_error_code(error::general)); - return; - } - - std::istream input(&m_proxy_data->read_buf); - - m_proxy_data->res.consume(input); - - if (!m_proxy_data->res.headers_ready()) { - // we read until the headers were done in theory but apparently - // they aren't. Internal endpoint error. - callback(make_error_code(error::general)); - return; - } - - m_alog->write(log::alevel::devel,m_proxy_data->res.raw()); - - if (m_proxy_data->res.get_status_code() != http::status_code::ok) { - // got an error response back - // TODO: expose this error in a programmatically accessible way? - // if so, see below for an option on how to do this. - std::stringstream s; - s << "Proxy connection error: " - << m_proxy_data->res.get_status_code() - << " (" - << m_proxy_data->res.get_status_msg() - << ")"; - m_elog->write(log::elevel::info,s.str()); - callback(make_error_code(error::proxy_failed)); - return; - } - - // we have successfully established a connection to the proxy, now - // we can continue and the proxy will transparently forward the - // WebSocket connection. - - // TODO: decide if we want an on_proxy callback that would allow - // access to the proxy response. - - // free the proxy buffers and req/res objects as they aren't needed - // anymore - m_proxy_data.reset(); - - // Continue with post proxy initialization - post_init(callback); - } - } - - /// read at least num_bytes bytes into buf and then call handler. - void async_read_at_least(size_t num_bytes, char *buf, size_t len, - read_handler handler) - { - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "asio async_read_at_least: " << num_bytes; - m_alog->write(log::alevel::devel,s.str()); - } - - // TODO: safety vs speed ? - // maybe move into an if devel block - /*if (num_bytes > len) { - m_elog->write(log::elevel::devel, - "asio async_read_at_least error::invalid_num_bytes"); - handler(make_error_code(transport::error::invalid_num_bytes), - size_t(0)); - return; - }*/ - - if (config::enable_multithreading) { - lib::asio::async_read( - socket_con_type::get_socket(), - lib::asio::buffer(buf,len), - lib::asio::transfer_at_least(num_bytes), - m_strand->wrap(make_custom_alloc_handler( - m_read_handler_allocator, - lib::bind( - &type::handle_async_read, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - )) - ); - } else { - lib::asio::async_read( - socket_con_type::get_socket(), - lib::asio::buffer(buf,len), - lib::asio::transfer_at_least(num_bytes), - make_custom_alloc_handler( - m_read_handler_allocator, - lib::bind( - &type::handle_async_read, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - ) - ); - } - - } - - void handle_async_read(read_handler handler, lib::asio::error_code const & ec, - size_t bytes_transferred) - { - m_alog->write(log::alevel::devel, "asio con handle_async_read"); - - // translate asio error codes into more lib::error_codes - lib::error_code tec; - if (ec == lib::asio::error::eof) { - tec = make_error_code(transport::error::eof); - } else if (ec) { - // We don't know much more about the error at this point. As our - // socket/security policy if it knows more: - tec = socket_con_type::translate_ec(ec); - m_tec = ec; - - if (tec == transport::error::tls_error || - tec == transport::error::pass_through) - { - // These are aggregate/catch all errors. Log some human readable - // information to the info channel to give library users some - // more details about why the upstream method may have failed. - log_err(log::elevel::info,"asio async_read_at_least",ec); - } - } - if (handler) { - handler(tec,bytes_transferred); - } else { - // This can happen in cases where the connection is terminated while - // the transport is waiting on a read. - m_alog->write(log::alevel::devel, - "handle_async_read called with null read handler"); - } - } - - /// Initiate a potentially asyncronous write of the given buffer - void async_write(const char* buf, size_t len, write_handler handler) { - m_bufs.push_back(lib::asio::buffer(buf,len)); - - if (config::enable_multithreading) { - lib::asio::async_write( - socket_con_type::get_socket(), - m_bufs, - m_strand->wrap(make_custom_alloc_handler( - m_write_handler_allocator, - lib::bind( - &type::handle_async_write, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - )) - ); - } else { - lib::asio::async_write( - socket_con_type::get_socket(), - m_bufs, - make_custom_alloc_handler( - m_write_handler_allocator, - lib::bind( - &type::handle_async_write, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - ) - ); - } - } - - /// Initiate a potentially asyncronous write of the given buffers - void async_write(std::vector const & bufs, write_handler handler) { - std::vector::const_iterator it; - - for (it = bufs.begin(); it != bufs.end(); ++it) { - m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len)); - } - - if (config::enable_multithreading) { - lib::asio::async_write( - socket_con_type::get_socket(), - m_bufs, - m_strand->wrap(make_custom_alloc_handler( - m_write_handler_allocator, - lib::bind( - &type::handle_async_write, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - )) - ); - } else { - lib::asio::async_write( - socket_con_type::get_socket(), - m_bufs, - make_custom_alloc_handler( - m_write_handler_allocator, - lib::bind( - &type::handle_async_write, get_shared(), - handler, - lib::placeholders::_1, lib::placeholders::_2 - ) - ) - ); - } - } - - /// Async write callback - /** - * @param ec The status code - * @param bytes_transferred The number of bytes read - */ - void handle_async_write(write_handler handler, lib::asio::error_code const & ec, size_t) { - m_bufs.clear(); - lib::error_code tec; - if (ec) { - log_err(log::elevel::info,"asio async_write",ec); - tec = make_error_code(transport::error::pass_through); - } - if (handler) { - handler(tec); - } else { - // This can happen in cases where the connection is terminated while - // the transport is waiting on a read. - m_alog->write(log::alevel::devel, - "handle_async_write called with null write handler"); - } - } - - /// Set Connection Handle - /** - * See common/connection_hdl.hpp for information - * - * @param hdl A connection_hdl that the transport will use to refer - * to itself - */ - void set_handle(connection_hdl hdl) { - m_connection_hdl = hdl; - socket_con_type::set_handle(hdl); - } - - /// Trigger the on_interrupt handler - /** - * This needs to be thread safe - */ - lib::error_code interrupt(interrupt_handler handler) { - if (config::enable_multithreading) { - m_io_service->post(m_strand->wrap(handler)); - } else { - m_io_service->post(handler); - } - return lib::error_code(); - } - - lib::error_code dispatch(dispatch_handler handler) { - if (config::enable_multithreading) { - m_io_service->post(m_strand->wrap(handler)); - } else { - m_io_service->post(handler); - } - return lib::error_code(); - } - - /*void handle_interrupt(interrupt_handler handler) { - handler(); - }*/ - - /// close and clean up the underlying socket - void async_shutdown(shutdown_handler callback) { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel,"asio connection async_shutdown"); - } - - timer_ptr shutdown_timer; - shutdown_timer = set_timer( - config::timeout_socket_shutdown, - lib::bind( - &type::handle_async_shutdown_timeout, - get_shared(), - shutdown_timer, - callback, - lib::placeholders::_1 - ) - ); - - socket_con_type::async_shutdown( - lib::bind( - &type::handle_async_shutdown, - get_shared(), - shutdown_timer, - callback, - lib::placeholders::_1 - ) - ); - } - - /// Async shutdown timeout handler - /** - * @param shutdown_timer A pointer to the timer to keep it in scope - * @param callback The function to call back - * @param ec The status code - */ - void handle_async_shutdown_timeout(timer_ptr, init_handler callback, - lib::error_code const & ec) - { - lib::error_code ret_ec; - - if (ec) { - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel, - "asio socket shutdown timer cancelled"); - return; - } - - log_err(log::elevel::devel,"asio handle_async_shutdown_timeout",ec); - ret_ec = ec; - } else { - ret_ec = make_error_code(transport::error::timeout); - } - - m_alog->write(log::alevel::devel, - "Asio transport socket shutdown timed out"); - cancel_socket_checked(); - callback(ret_ec); - } - - void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler - callback, lib::asio::error_code const & ec) - { - if (ec == lib::asio::error::operation_aborted || - lib::asio::is_neg(shutdown_timer->expires_from_now())) - { - m_alog->write(log::alevel::devel,"async_shutdown cancelled"); - return; - } - - shutdown_timer->cancel(); - - lib::error_code tec; - if (ec) { - if (ec == lib::asio::error::not_connected) { - // The socket was already closed when we tried to close it. This - // happens periodically (usually if a read or write fails - // earlier and if it is a real error will be caught at another - // level of the stack. - } else { - // We don't know anything more about this error, give our - // socket/security policy a crack at it. - tec = socket_con_type::translate_ec(ec); - m_tec = ec; - - // all other errors are effectively pass through errors of - // some sort so print some detail on the info channel for - // library users to look up if needed. - log_err(log::elevel::info,"asio async_shutdown",ec); - } - } else { - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel, - "asio con handle_async_shutdown"); - } - } - callback(tec); - } - - /// Cancel the underlying socket and log any errors - void cancel_socket_checked() { - lib::asio::error_code cec = socket_con_type::cancel_socket(); - if (cec) { - if (cec == lib::asio::error::operation_not_supported) { - // cancel not supported on this OS, ignore and log at dev level - m_alog->write(log::alevel::devel, "socket cancel not supported"); - } else { - log_err(log::elevel::warn, "socket cancel failed", cec); - } - } - } - -private: - /// Convenience method for logging the code and message for an error_code - template - void log_err(log::level l, const char * msg, const error_type & ec) { - std::stringstream s; - s << msg << " error: " << ec << " (" << ec.message() << ")"; - m_elog->write(l,s.str()); - } - - // static settings - const bool m_is_server; - lib::shared_ptr m_alog; - lib::shared_ptr m_elog; - - struct proxy_data { - proxy_data() : timeout_proxy(config::timeout_proxy) {} - - request_type req; - response_type res; - std::string write_buf; - lib::asio::streambuf read_buf; - long timeout_proxy; - timer_ptr timer; - }; - - std::string m_proxy; - lib::shared_ptr m_proxy_data; - - // transport resources - io_service_ptr m_io_service; - strand_ptr m_strand; - connection_hdl m_connection_hdl; - - std::vector m_bufs; - - /// Detailed internal error code - lib::asio::error_code m_tec; - - // Handlers - tcp_init_handler m_tcp_pre_init_handler; - tcp_init_handler m_tcp_post_init_handler; - - handler_allocator m_read_handler_allocator; - handler_allocator m_write_handler_allocator; -}; - - -} // namespace asio -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP +/* + * 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_CON_HPP +#define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace websocketpp { +namespace transport { +namespace asio { + +typedef lib::function tcp_init_handler; + +/// Asio based connection transport component +/** + * transport::asio::connection implements a connection transport component using + * Asio that works with the transport::asio::endpoint endpoint transport + * component. + */ +template +class connection : public config::socket_type::socket_con_type { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// Type of the socket connection component + typedef typename config::socket_type::socket_con_type socket_con_type; + /// Type of a shared pointer to the socket connection component + typedef typename socket_con_type::ptr socket_con_ptr; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + typedef typename config::request_type request_type; + typedef typename request_type::ptr request_ptr; + typedef typename config::response_type response_type; + typedef typename response_type::ptr response_ptr; + + /// Type of a pointer to the Asio io_service being used + typedef lib::asio::io_service * io_service_ptr; + /// Type of a pointer to the Asio io_service::strand being used + typedef lib::shared_ptr strand_ptr; + /// Type of a pointer to the Asio timer class + typedef lib::shared_ptr timer_ptr; + + // connection is friends with its associated endpoint to allow the endpoint + // to call private/protected utility methods that we don't want to expose + // to the public api. + friend class endpoint; + + // generate and manage our own io_service + explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) + : m_is_server(is_server) + , m_alog(alog) + , m_elog(elog) + { + m_alog->write(log::alevel::devel,"asio con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return lib::static_pointer_cast(socket_con_type::get_shared()); + } + + bool is_secure() const { + return socket_con_type::is_secure(); + } + + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * This transport policy doesn't use the uri except to forward it to the + * socket layer. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr u) { + socket_con_type::set_uri(u); + } + + /// Sets the tcp pre init handler + /** + * The tcp pre init handler is called after the raw tcp connection has been + * established but before any additional wrappers (proxy connects, TLS + * handshakes, etc) have been performed. + * + * @since 0.3.0 + * + * @param h The handler to call on tcp pre init. + */ + void set_tcp_pre_init_handler(tcp_init_handler h) { + m_tcp_pre_init_handler = h; + } + + /// Sets the tcp pre init handler (deprecated) + /** + * The tcp pre init handler is called after the raw tcp connection has been + * established but before any additional wrappers (proxy connects, TLS + * handshakes, etc) have been performed. + * + * @deprecated Use set_tcp_pre_init_handler instead + * + * @param h The handler to call on tcp pre init. + */ + void set_tcp_init_handler(tcp_init_handler h) { + set_tcp_pre_init_handler(h); + } + + /// Sets the tcp post init handler + /** + * The tcp post init handler is called after the tcp connection has been + * established and all additional wrappers (proxy connects, TLS handshakes, + * etc have been performed. This is fired before any bytes are read or any + * WebSocket specific handshake logic has been performed. + * + * @since 0.3.0 + * + * @param h The handler to call on tcp post init. + */ + void set_tcp_post_init_handler(tcp_init_handler h) { + m_tcp_post_init_handler = h; + } + + /// Set the proxy to connect through (exception free) + /** + * The URI passed should be a complete URI including scheme. For example: + * http://proxy.example.com:8080/ + * + * The proxy must be set up as an explicit (CONNECT) proxy allowed to + * connect to the port you specify. Traffic to the proxy is not encrypted. + * + * @param uri The full URI of the proxy to connect to. + * + * @param ec A status value + */ + void set_proxy(std::string const & uri, lib::error_code & ec) { + // TODO: return errors for illegal URIs here? + // TODO: should https urls be illegal for the moment? + m_proxy = uri; + m_proxy_data = lib::make_shared(); + ec = lib::error_code(); + } + + /// Set the proxy to connect through (exception) + void set_proxy(std::string const & uri) { + lib::error_code ec; + set_proxy(uri,ec); + if (ec) { throw exception(ec); } + } + + /// Set the basic auth credentials to use (exception free) + /** + * The URI passed should be a complete URI including scheme. For example: + * http://proxy.example.com:8080/ + * + * The proxy must be set up as an explicit proxy + * + * @param username The username to send + * + * @param password The password to send + * + * @param ec A status value + */ + void set_proxy_basic_auth(std::string const & username, std::string const & + password, lib::error_code & ec) + { + if (!m_proxy_data) { + ec = make_error_code(websocketpp::error::invalid_state); + return; + } + + // TODO: username can't contain ':' + std::string val = "Basic "+base64_encode(username + ":" + password); + m_proxy_data->req.replace_header("Proxy-Authorization",val); + ec = lib::error_code(); + } + + /// Set the basic auth credentials to use (exception) + void set_proxy_basic_auth(std::string const & username, std::string const & + password) + { + lib::error_code ec; + set_proxy_basic_auth(username,password,ec); + if (ec) { throw exception(ec); } + } + + /// Set the proxy timeout duration (exception free) + /** + * Duration is in milliseconds. Default value is based on the transport + * config + * + * @param duration The number of milliseconds to wait before aborting the + * proxy connection. + * + * @param ec A status value + */ + void set_proxy_timeout(long duration, lib::error_code & ec) { + if (!m_proxy_data) { + ec = make_error_code(websocketpp::error::invalid_state); + return; + } + + m_proxy_data->timeout_proxy = duration; + ec = lib::error_code(); + } + + /// Set the proxy timeout duration (exception) + void set_proxy_timeout(long duration) { + lib::error_code ec; + set_proxy_timeout(duration,ec); + if (ec) { throw exception(ec); } + } + + std::string const & get_proxy() const { + return m_proxy; + } + + /// Get the remote endpoint address + /** + * The iostream transport has no information about the ultimate remote + * endpoint. It will return the string "iostream transport". To indicate + * this. + * + * TODO: allow user settable remote endpoint addresses if this seems useful + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + lib::error_code ec; + + std::string ret = socket_con_type::get_remote_endpoint(ec); + + if (ec) { + m_elog->write(log::elevel::info,ret); + return "Unknown"; + } else { + return ret; + } + } + + /// Get the connection handle + connection_hdl get_handle() const { + return m_connection_hdl; + } + + /// Call back a function after a period of time. + /** + * Sets a timer that calls back a function after the specified period of + * milliseconds. Returns a handle that can be used to cancel the timer. + * A cancelled timer will return the error code error::operation_aborted + * A timer that expired will return no error. + * + * @param duration Length of time to wait in milliseconds + * + * @param callback The function to call back when the timer has expired + * + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long duration, timer_handler callback) { + timer_ptr new_timer( + new lib::asio::steady_timer( + *m_io_service, + lib::asio::milliseconds(duration)) + ); + + if (config::enable_multithreading) { + new_timer->async_wait(m_strand->wrap(lib::bind( + &type::handle_timer, get_shared(), + new_timer, + callback, + lib::placeholders::_1 + ))); + } else { + new_timer->async_wait(lib::bind( + &type::handle_timer, get_shared(), + new_timer, + callback, + lib::placeholders::_1 + )); + } + + return new_timer; + } + + /// Timer callback + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * TODO: candidate for protected status + * + * @param post_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec The status code + */ + void handle_timer(timer_ptr, timer_handler callback, + lib::asio::error_code const & ec) + { + if (ec) { + if (ec == lib::asio::error::operation_aborted) { + callback(make_error_code(transport::error::operation_aborted)); + } else { + log_err(log::elevel::info,"asio handle_timer",ec); + callback(make_error_code(error::pass_through)); + } + } else { + callback(lib::error_code()); + } + } + + /// Get a pointer to this connection's strand + strand_ptr get_strand() { + return m_strand; + } + + /// Get the internal transport error code for a closed/failed connection + /** + * Retrieves a machine readable detailed error code indicating the reason + * that the connection was closed or failed. Valid only after the close or + * fail handler is called. + * + * Primarily used if you are using mismatched asio / system_error + * implementations such as `boost::asio` with `std::system_error`. In these + * cases the transport error type is different than the library error type + * and some WebSocket++ functions that return transport errors via the + * library error code type will be coerced into a catch all `pass_through` + * or `tls_error` error. This method will return the original machine + * readable transport error in the native type. + * + * @since 0.7.0 + * + * @return Error code indicating the reason the connection was closed or + * failed + */ + lib::asio::error_code get_transport_ec() const { + return m_tec; + } + + /// Initialize transport for reading + /** + * init_asio is called once immediately after construction to initialize + * Asio components to the io_service + * + * The transport initialization sequence consists of the following steps: + * - Pre-init: the underlying socket is initialized to the point where + * bytes may be written. No bytes are actually written in this stage + * - Proxy negotiation: if a proxy is set, a request is made to it to start + * a tunnel to the final destination. This stage ends when the proxy is + * ready to forward the + * next byte to the remote endpoint. + * - Post-init: Perform any i/o with the remote endpoint, such as setting up + * tunnels for encryption. This stage ends when the connection is ready to + * read or write the WebSocket handshakes. At this point the original + * callback function is called. + */ +protected: + void init(init_handler callback) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection init"); + } + + // TODO: pre-init timeout. Right now no implemented socket policies + // actually have an asyncronous pre-init + + socket_con_type::pre_init( + lib::bind( + &type::handle_pre_init, + get_shared(), + callback, + lib::placeholders::_1 + ) + ); + } + + /// initialize the proxy buffers and http parsers + /** + * + * @param authority The address of the server we want the proxy to tunnel to + * in the format of a URI authority (host:port) + * + * @return Status code indicating what errors occurred, if any + */ + lib::error_code proxy_init(std::string const & authority) { + if (!m_proxy_data) { + return websocketpp::error::make_error_code( + websocketpp::error::invalid_state); + } + m_proxy_data->req.set_version("HTTP/1.1"); + m_proxy_data->req.set_method("CONNECT"); + + m_proxy_data->req.set_uri(authority); + m_proxy_data->req.replace_header("Host",authority); + + return lib::error_code(); + } + + /// Finish constructing the transport + /** + * init_asio is called once immediately after construction to initialize + * Asio components to the io_service. + * + * @param io_service A pointer to the io_service to register with this + * connection + * + * @return Status code for the success or failure of the initialization + */ + lib::error_code init_asio (io_service_ptr io_service) { + m_io_service = io_service; + + if (config::enable_multithreading) { + m_strand.reset(new lib::asio::io_service::strand(*io_service)); + } + + lib::error_code ec = socket_con_type::init_asio(io_service, m_strand, + m_is_server); + + return ec; + } + + void handle_pre_init(init_handler callback, lib::error_code const & ec) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection handle pre_init"); + } + + if (m_tcp_pre_init_handler) { + m_tcp_pre_init_handler(m_connection_hdl); + } + + if (ec) { + callback(ec); + } + + // If we have a proxy set issue a proxy connect, otherwise skip to + // post_init + if (!m_proxy.empty()) { + proxy_write(callback); + } else { + post_init(callback); + } + } + + void post_init(init_handler callback) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection post_init"); + } + + timer_ptr post_timer; + + if (config::timeout_socket_post_init > 0) { + post_timer = set_timer( + config::timeout_socket_post_init, + lib::bind( + &type::handle_post_init_timeout, + get_shared(), + post_timer, + callback, + lib::placeholders::_1 + ) + ); + } + + socket_con_type::post_init( + lib::bind( + &type::handle_post_init, + get_shared(), + post_timer, + callback, + lib::placeholders::_1 + ) + ); + } + + /// Post init timeout callback + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param post_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec The status code + */ + void handle_post_init_timeout(timer_ptr, init_handler callback, + lib::error_code const & ec) + { + lib::error_code ret_ec; + + if (ec) { + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel, + "asio post init timer cancelled"); + return; + } + + log_err(log::elevel::devel,"asio handle_post_init_timeout",ec); + ret_ec = ec; + } else { + if (socket_con_type::get_ec()) { + ret_ec = socket_con_type::get_ec(); + } else { + ret_ec = make_error_code(transport::error::timeout); + } + } + + m_alog->write(log::alevel::devel, "Asio transport post-init timed out"); + cancel_socket_checked(); + callback(ret_ec); + } + + /// Post init timeout callback + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param post_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec The status code + */ + void handle_post_init(timer_ptr post_timer, init_handler callback, + lib::error_code const & ec) + { + if (ec == transport::error::operation_aborted || + (post_timer && lib::asio::is_neg(post_timer->expires_from_now()))) + { + m_alog->write(log::alevel::devel,"post_init cancelled"); + return; + } + + if (post_timer) { + post_timer->cancel(); + } + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection handle_post_init"); + } + + if (m_tcp_post_init_handler) { + m_tcp_post_init_handler(m_connection_hdl); + } + + callback(ec); + } + + void proxy_write(init_handler callback) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection proxy_write"); + } + + if (!m_proxy_data) { + m_elog->write(log::elevel::library, + "assertion failed: !m_proxy_data in asio::connection::proxy_write"); + callback(make_error_code(error::general)); + return; + } + + m_proxy_data->write_buf = m_proxy_data->req.raw(); + + m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(), + m_proxy_data->write_buf.size())); + + m_alog->write(log::alevel::devel,m_proxy_data->write_buf); + + // Set a timer so we don't wait forever for the proxy to respond + m_proxy_data->timer = this->set_timer( + m_proxy_data->timeout_proxy, + lib::bind( + &type::handle_proxy_timeout, + get_shared(), + callback, + lib::placeholders::_1 + ) + ); + + // Send proxy request + if (config::enable_multithreading) { + lib::asio::async_write( + socket_con_type::get_next_layer(), + m_bufs, + m_strand->wrap(lib::bind( + &type::handle_proxy_write, get_shared(), + callback, + lib::placeholders::_1 + )) + ); + } else { + lib::asio::async_write( + socket_con_type::get_next_layer(), + m_bufs, + lib::bind( + &type::handle_proxy_write, get_shared(), + callback, + lib::placeholders::_1 + ) + ); + } + } + + void handle_proxy_timeout(init_handler callback, lib::error_code const & ec) + { + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel, + "asio handle_proxy_write timer cancelled"); + return; + } else if (ec) { + log_err(log::elevel::devel,"asio handle_proxy_write",ec); + callback(ec); + } else { + m_alog->write(log::alevel::devel, + "asio handle_proxy_write timer expired"); + cancel_socket_checked(); + callback(make_error_code(transport::error::timeout)); + } + } + + void handle_proxy_write(init_handler callback, + lib::asio::error_code const & ec) + { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel, + "asio connection handle_proxy_write"); + } + + m_bufs.clear(); + + // Timer expired or the operation was aborted for some reason. + // Whatever aborted it will be issuing the callback so we are safe to + // return + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) + { + m_elog->write(log::elevel::devel,"write operation aborted"); + return; + } + + if (ec) { + log_err(log::elevel::info,"asio handle_proxy_write",ec); + m_proxy_data->timer->cancel(); + callback(make_error_code(error::pass_through)); + return; + } + + proxy_read(callback); + } + + void proxy_read(init_handler callback) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection proxy_read"); + } + + if (!m_proxy_data) { + m_elog->write(log::elevel::library, + "assertion failed: !m_proxy_data in asio::connection::proxy_read"); + m_proxy_data->timer->cancel(); + callback(make_error_code(error::general)); + return; + } + + if (config::enable_multithreading) { + lib::asio::async_read_until( + socket_con_type::get_next_layer(), + m_proxy_data->read_buf, + "\r\n\r\n", + m_strand->wrap(lib::bind( + &type::handle_proxy_read, get_shared(), + callback, + lib::placeholders::_1, lib::placeholders::_2 + )) + ); + } else { + lib::asio::async_read_until( + socket_con_type::get_next_layer(), + m_proxy_data->read_buf, + "\r\n\r\n", + lib::bind( + &type::handle_proxy_read, get_shared(), + callback, + lib::placeholders::_1, lib::placeholders::_2 + ) + ); + } + } + + /// Proxy read callback + /** + * @param init_handler The function to call back + * @param ec The status code + * @param bytes_transferred The number of bytes read + */ + void handle_proxy_read(init_handler callback, + lib::asio::error_code const & ec, size_t) + { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel, + "asio connection handle_proxy_read"); + } + + // Timer expired or the operation was aborted for some reason. + // Whatever aborted it will be issuing the callback so we are safe to + // return + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) + { + m_elog->write(log::elevel::devel,"read operation aborted"); + return; + } + + // At this point there is no need to wait for the timer anymore + m_proxy_data->timer->cancel(); + + if (ec) { + m_elog->write(log::elevel::info, + "asio handle_proxy_read error: "+ec.message()); + callback(make_error_code(error::pass_through)); + } else { + if (!m_proxy_data) { + m_elog->write(log::elevel::library, + "assertion failed: !m_proxy_data in asio::connection::handle_proxy_read"); + callback(make_error_code(error::general)); + return; + } + + std::istream input(&m_proxy_data->read_buf); + + m_proxy_data->res.consume(input); + + if (!m_proxy_data->res.headers_ready()) { + // we read until the headers were done in theory but apparently + // they aren't. Internal endpoint error. + callback(make_error_code(error::general)); + return; + } + + m_alog->write(log::alevel::devel,m_proxy_data->res.raw()); + + if (m_proxy_data->res.get_status_code() != http::status_code::ok) { + // got an error response back + // TODO: expose this error in a programmatically accessible way? + // if so, see below for an option on how to do this. + std::stringstream s; + s << "Proxy connection error: " + << m_proxy_data->res.get_status_code() + << " (" + << m_proxy_data->res.get_status_msg() + << ")"; + m_elog->write(log::elevel::info,s.str()); + callback(make_error_code(error::proxy_failed)); + return; + } + + // we have successfully established a connection to the proxy, now + // we can continue and the proxy will transparently forward the + // WebSocket connection. + + // TODO: decide if we want an on_proxy callback that would allow + // access to the proxy response. + + // free the proxy buffers and req/res objects as they aren't needed + // anymore + m_proxy_data.reset(); + + // Continue with post proxy initialization + post_init(callback); + } + } + + /// read at least num_bytes bytes into buf and then call handler. + void async_read_at_least(size_t num_bytes, char *buf, size_t len, + read_handler handler) + { + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "asio async_read_at_least: " << num_bytes; + m_alog->write(log::alevel::devel,s.str()); + } + + // TODO: safety vs speed ? + // maybe move into an if devel block + /*if (num_bytes > len) { + m_elog->write(log::elevel::devel, + "asio async_read_at_least error::invalid_num_bytes"); + handler(make_error_code(transport::error::invalid_num_bytes), + size_t(0)); + return; + }*/ + + if (config::enable_multithreading) { + lib::asio::async_read( + socket_con_type::get_socket(), + lib::asio::buffer(buf,len), + lib::asio::transfer_at_least(num_bytes), + m_strand->wrap(make_custom_alloc_handler( + m_read_handler_allocator, + lib::bind( + &type::handle_async_read, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + )) + ); + } else { + lib::asio::async_read( + socket_con_type::get_socket(), + lib::asio::buffer(buf,len), + lib::asio::transfer_at_least(num_bytes), + make_custom_alloc_handler( + m_read_handler_allocator, + lib::bind( + &type::handle_async_read, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + ) + ); + } + + } + + void handle_async_read(read_handler handler, lib::asio::error_code const & ec, + size_t bytes_transferred) + { + m_alog->write(log::alevel::devel, "asio con handle_async_read"); + + // translate asio error codes into more lib::error_codes + lib::error_code tec; + if (ec == lib::asio::error::eof) { + tec = make_error_code(transport::error::eof); + } else if (ec) { + // We don't know much more about the error at this point. As our + // socket/security policy if it knows more: + tec = socket_con_type::translate_ec(ec); + m_tec = ec; + + if (tec == transport::error::tls_error || + tec == transport::error::pass_through) + { + // These are aggregate/catch all errors. Log some human readable + // information to the info channel to give library users some + // more details about why the upstream method may have failed. + log_err(log::elevel::info,"asio async_read_at_least",ec); + } + } + if (handler) { + handler(tec,bytes_transferred); + } else { + // This can happen in cases where the connection is terminated while + // the transport is waiting on a read. + m_alog->write(log::alevel::devel, + "handle_async_read called with null read handler"); + } + } + + /// Initiate a potentially asyncronous write of the given buffer + void async_write(const char* buf, size_t len, write_handler handler) { + m_bufs.push_back(lib::asio::buffer(buf,len)); + + if (config::enable_multithreading) { + lib::asio::async_write( + socket_con_type::get_socket(), + m_bufs, + m_strand->wrap(make_custom_alloc_handler( + m_write_handler_allocator, + lib::bind( + &type::handle_async_write, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + )) + ); + } else { + lib::asio::async_write( + socket_con_type::get_socket(), + m_bufs, + make_custom_alloc_handler( + m_write_handler_allocator, + lib::bind( + &type::handle_async_write, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + ) + ); + } + } + + /// Initiate a potentially asyncronous write of the given buffers + void async_write(std::vector const & bufs, write_handler handler) { + std::vector::const_iterator it; + + for (it = bufs.begin(); it != bufs.end(); ++it) { + m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len)); + } + + if (config::enable_multithreading) { + lib::asio::async_write( + socket_con_type::get_socket(), + m_bufs, + m_strand->wrap(make_custom_alloc_handler( + m_write_handler_allocator, + lib::bind( + &type::handle_async_write, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + )) + ); + } else { + lib::asio::async_write( + socket_con_type::get_socket(), + m_bufs, + make_custom_alloc_handler( + m_write_handler_allocator, + lib::bind( + &type::handle_async_write, get_shared(), + handler, + lib::placeholders::_1, lib::placeholders::_2 + ) + ) + ); + } + } + + /// Async write callback + /** + * @param ec The status code + * @param bytes_transferred The number of bytes read + */ + void handle_async_write(write_handler handler, lib::asio::error_code const & ec, size_t) { + m_bufs.clear(); + lib::error_code tec; + if (ec) { + log_err(log::elevel::info,"asio async_write",ec); + tec = make_error_code(transport::error::pass_through); + } + if (handler) { + handler(tec); + } else { + // This can happen in cases where the connection is terminated while + // the transport is waiting on a read. + m_alog->write(log::alevel::devel, + "handle_async_write called with null write handler"); + } + } + + /// Set Connection Handle + /** + * See common/connection_hdl.hpp for information + * + * @param hdl A connection_hdl that the transport will use to refer + * to itself + */ + void set_handle(connection_hdl hdl) { + m_connection_hdl = hdl; + socket_con_type::set_handle(hdl); + } + + /// Trigger the on_interrupt handler + /** + * This needs to be thread safe + */ + lib::error_code interrupt(interrupt_handler handler) { + if (config::enable_multithreading) { + m_io_service->post(m_strand->wrap(handler)); + } else { + m_io_service->post(handler); + } + return lib::error_code(); + } + + lib::error_code dispatch(dispatch_handler handler) { + if (config::enable_multithreading) { + m_io_service->post(m_strand->wrap(handler)); + } else { + m_io_service->post(handler); + } + return lib::error_code(); + } + + /*void handle_interrupt(interrupt_handler handler) { + handler(); + }*/ + + /// close and clean up the underlying socket + void async_shutdown(shutdown_handler callback) { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel,"asio connection async_shutdown"); + } + + timer_ptr shutdown_timer; + shutdown_timer = set_timer( + config::timeout_socket_shutdown, + lib::bind( + &type::handle_async_shutdown_timeout, + get_shared(), + shutdown_timer, + callback, + lib::placeholders::_1 + ) + ); + + socket_con_type::async_shutdown( + lib::bind( + &type::handle_async_shutdown, + get_shared(), + shutdown_timer, + callback, + lib::placeholders::_1 + ) + ); + } + + /// Async shutdown timeout handler + /** + * @param shutdown_timer A pointer to the timer to keep it in scope + * @param callback The function to call back + * @param ec The status code + */ + void handle_async_shutdown_timeout(timer_ptr, init_handler callback, + lib::error_code const & ec) + { + lib::error_code ret_ec; + + if (ec) { + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel, + "asio socket shutdown timer cancelled"); + return; + } + + log_err(log::elevel::devel,"asio handle_async_shutdown_timeout",ec); + ret_ec = ec; + } else { + ret_ec = make_error_code(transport::error::timeout); + } + + m_alog->write(log::alevel::devel, + "Asio transport socket shutdown timed out"); + cancel_socket_checked(); + callback(ret_ec); + } + + void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler + callback, lib::asio::error_code const & ec) + { + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(shutdown_timer->expires_from_now())) + { + m_alog->write(log::alevel::devel,"async_shutdown cancelled"); + return; + } + + shutdown_timer->cancel(); + + lib::error_code tec; + if (ec) { + if (ec == lib::asio::error::not_connected) { + // The socket was already closed when we tried to close it. This + // happens periodically (usually if a read or write fails + // earlier and if it is a real error will be caught at another + // level of the stack. + } else { + // We don't know anything more about this error, give our + // socket/security policy a crack at it. + tec = socket_con_type::translate_ec(ec); + m_tec = ec; + + // all other errors are effectively pass through errors of + // some sort so print some detail on the info channel for + // library users to look up if needed. + log_err(log::elevel::info,"asio async_shutdown",ec); + } + } else { + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel, + "asio con handle_async_shutdown"); + } + } + callback(tec); + } + + /// Cancel the underlying socket and log any errors + void cancel_socket_checked() { + lib::asio::error_code cec = socket_con_type::cancel_socket(); + if (cec) { + if (cec == lib::asio::error::operation_not_supported) { + // cancel not supported on this OS, ignore and log at dev level + m_alog->write(log::alevel::devel, "socket cancel not supported"); + } else { + log_err(log::elevel::warn, "socket cancel failed", cec); + } + } + } + +private: + /// Convenience method for logging the code and message for an error_code + template + void log_err(log::level l, const char * msg, const error_type & ec) { + std::stringstream s; + s << msg << " error: " << ec << " (" << ec.message() << ")"; + m_elog->write(l,s.str()); + } + + // static settings + const bool m_is_server; + lib::shared_ptr m_alog; + lib::shared_ptr m_elog; + + struct proxy_data { + proxy_data() : timeout_proxy(config::timeout_proxy) {} + + request_type req; + response_type res; + std::string write_buf; + lib::asio::streambuf read_buf; + long timeout_proxy; + timer_ptr timer; + }; + + std::string m_proxy; + lib::shared_ptr m_proxy_data; + + // transport resources + io_service_ptr m_io_service; + strand_ptr m_strand; + connection_hdl m_connection_hdl; + + std::vector m_bufs; + + /// Detailed internal error code + lib::asio::error_code m_tec; + + // Handlers + tcp_init_handler m_tcp_pre_init_handler; + tcp_init_handler m_tcp_post_init_handler; + + handler_allocator m_read_handler_allocator; + handler_allocator m_write_handler_allocator; +}; + + +} // namespace asio +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/endpoint.hpp index bb6cbd9..94509ad 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/endpoint.hpp @@ -1,1182 +1,1182 @@ -/* - * 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_HPP -#define WEBSOCKETPP_TRANSPORT_ASIO_HPP - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace asio { - -/// Asio based endpoint transport component -/** - * transport::asio::endpoint implements an endpoint transport component using - * Asio. - */ -template -class endpoint : public config::socket_type { -public: - /// Type of this endpoint transport component - typedef endpoint type; - - /// Type of the concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of the socket policy - typedef typename config::socket_type socket_type; - /// Type of the error logging policy - typedef typename config::elog_type elog_type; - /// Type of the access logging policy - typedef typename config::alog_type alog_type; - - /// Type of the socket connection component - typedef typename socket_type::socket_con_type socket_con_type; - /// Type of a shared pointer to the socket connection component - typedef typename socket_con_type::ptr socket_con_ptr; - - /// Type of the connection transport component associated with this - /// endpoint transport component - typedef asio::connection transport_con_type; - /// Type of a shared pointer to the connection transport component - /// associated with this endpoint transport component - typedef typename transport_con_type::ptr transport_con_ptr; - - /// Type of a pointer to the ASIO io_service being used - typedef lib::asio::io_service * io_service_ptr; - /// Type of a shared pointer to the acceptor being used - typedef lib::shared_ptr acceptor_ptr; - /// Type of a shared pointer to the resolver being used - typedef lib::shared_ptr resolver_ptr; - /// Type of timer handle - typedef lib::shared_ptr timer_ptr; - /// Type of a shared pointer to an io_service work object - typedef lib::shared_ptr work_ptr; - - /// Type of socket pre-bind handler - typedef lib::function tcp_pre_bind_handler; - - // generate and manage our own io_service - explicit endpoint() - : m_io_service(NULL) - , m_external_io_service(false) - , m_listen_backlog(lib::asio::socket_base::max_connections) - , m_reuse_addr(false) - , m_state(UNINITIALIZED) - { - //std::cout << "transport::asio::endpoint constructor" << std::endl; - } - - ~endpoint() { - // clean up our io_service if we were initialized with an internal one. - - // Explicitly destroy local objects - m_acceptor.reset(); - m_resolver.reset(); - m_work.reset(); - if (m_state != UNINITIALIZED && !m_external_io_service) { - delete m_io_service; - } - } - - /// transport::asio objects are moveable but not copyable or assignable. - /// The following code sets this situation up based on whether or not we - /// have C++11 support or not -#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - endpoint(const endpoint & src) = delete; - endpoint& operator= (const endpoint & rhs) = delete; -#else -private: - endpoint(const endpoint & src); - endpoint & operator= (const endpoint & rhs); -public: -#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ - -#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ - endpoint (endpoint && src) - : config::socket_type(std::move(src)) - , m_tcp_pre_init_handler(src.m_tcp_pre_init_handler) - , m_tcp_post_init_handler(src.m_tcp_post_init_handler) - , m_io_service(src.m_io_service) - , m_external_io_service(src.m_external_io_service) - , m_acceptor(src.m_acceptor) - , m_listen_backlog(lib::asio::socket_base::max_connections) - , m_reuse_addr(src.m_reuse_addr) - , m_elog(src.m_elog) - , m_alog(src.m_alog) - , m_state(src.m_state) - { - src.m_io_service = NULL; - src.m_external_io_service = false; - src.m_acceptor = NULL; - src.m_state = UNINITIALIZED; - } - - /*endpoint & operator= (const endpoint && rhs) { - if (this != &rhs) { - m_io_service = rhs.m_io_service; - m_external_io_service = rhs.m_external_io_service; - m_acceptor = rhs.m_acceptor; - m_listen_backlog = rhs.m_listen_backlog; - m_reuse_addr = rhs.m_reuse_addr; - m_state = rhs.m_state; - - rhs.m_io_service = NULL; - rhs.m_external_io_service = false; - rhs.m_acceptor = NULL; - rhs.m_listen_backlog = lib::asio::socket_base::max_connections; - rhs.m_state = UNINITIALIZED; - - // TODO: this needs to be updated - } - return *this; - }*/ -#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ - - /// Return whether or not the endpoint produces secure connections. - bool is_secure() const { - return socket_type::is_secure(); - } - - /// initialize asio transport with external io_service (exception free) - /** - * Initialize the ASIO transport policy for this endpoint using the provided - * io_service object. asio_init must be called exactly once on any endpoint - * that uses transport::asio before it can be used. - * - * @param ptr A pointer to the io_service to use for asio events - * @param ec Set to indicate what error occurred, if any. - */ - void init_asio(io_service_ptr ptr, lib::error_code & ec) { - if (m_state != UNINITIALIZED) { - m_elog->write(log::elevel::library, - "asio::init_asio called from the wrong state"); - using websocketpp::error::make_error_code; - ec = make_error_code(websocketpp::error::invalid_state); - return; - } - - m_alog->write(log::alevel::devel,"asio::init_asio"); - - m_io_service = ptr; - m_external_io_service = true; - m_acceptor.reset(new lib::asio::ip::tcp::acceptor(*m_io_service)); - - m_state = READY; - ec = lib::error_code(); - } - - /// initialize asio transport with external io_service - /** - * Initialize the ASIO transport policy for this endpoint using the provided - * io_service object. asio_init must be called exactly once on any endpoint - * that uses transport::asio before it can be used. - * - * @param ptr A pointer to the io_service to use for asio events - */ - void init_asio(io_service_ptr ptr) { - lib::error_code ec; - init_asio(ptr,ec); - if (ec) { throw exception(ec); } - } - - /// Initialize asio transport with internal io_service (exception free) - /** - * This method of initialization will allocate and use an internally managed - * io_service. - * - * @see init_asio(io_service_ptr ptr) - * - * @param ec Set to indicate what error occurred, if any. - */ - void init_asio(lib::error_code & ec) { - // Use a smart pointer until the call is successful and ownership has - // successfully been taken. Use unique_ptr when available. - // TODO: remove the use of auto_ptr when C++98/03 support is no longer - // necessary. -#ifdef _WEBSOCKETPP_CPP11_MEMORY_ - lib::unique_ptr service(new lib::asio::io_service()); -#else - lib::auto_ptr service(new lib::asio::io_service()); -#endif - init_asio(service.get(), ec); - if( !ec ) service.release(); // Call was successful, transfer ownership - m_external_io_service = false; - } - - /// Initialize asio transport with internal io_service - /** - * This method of initialization will allocate and use an internally managed - * io_service. - * - * @see init_asio(io_service_ptr ptr) - */ - void init_asio() { - // Use a smart pointer until the call is successful and ownership has - // successfully been taken. Use unique_ptr when available. - // TODO: remove the use of auto_ptr when C++98/03 support is no longer - // necessary. -#ifdef _WEBSOCKETPP_CPP11_MEMORY_ - lib::unique_ptr service(new lib::asio::io_service()); -#else - lib::auto_ptr service(new lib::asio::io_service()); -#endif - init_asio( service.get() ); - // If control got this far without an exception, then ownership has successfully been taken - service.release(); - m_external_io_service = false; - } - - /// Sets the tcp pre bind handler - /** - * The tcp pre bind handler is called after the listen acceptor has - * been created but before the socket bind is performed. - * - * @since 0.8.0 - * - * @param h The handler to call on tcp pre bind init. - */ - void set_tcp_pre_bind_handler(tcp_pre_bind_handler h) { - m_tcp_pre_bind_handler = h; - } - - /// Sets the tcp pre init handler - /** - * The tcp pre init handler is called after the raw tcp connection has been - * established but before any additional wrappers (proxy connects, TLS - * handshakes, etc) have been performed. - * - * @since 0.3.0 - * - * @param h The handler to call on tcp pre init. - */ - void set_tcp_pre_init_handler(tcp_init_handler h) { - m_tcp_pre_init_handler = h; - } - - /// Sets the tcp pre init handler (deprecated) - /** - * The tcp pre init handler is called after the raw tcp connection has been - * established but before any additional wrappers (proxy connects, TLS - * handshakes, etc) have been performed. - * - * @deprecated Use set_tcp_pre_init_handler instead - * - * @param h The handler to call on tcp pre init. - */ - void set_tcp_init_handler(tcp_init_handler h) { - set_tcp_pre_init_handler(h); - } - - /// Sets the tcp post init handler - /** - * The tcp post init handler is called after the tcp connection has been - * established and all additional wrappers (proxy connects, TLS handshakes, - * etc have been performed. This is fired before any bytes are read or any - * WebSocket specific handshake logic has been performed. - * - * @since 0.3.0 - * - * @param h The handler to call on tcp post init. - */ - void set_tcp_post_init_handler(tcp_init_handler h) { - m_tcp_post_init_handler = h; - } - - /// Sets the maximum length of the queue of pending connections. - /** - * Sets the maximum length of the queue of pending connections. Increasing - * this will allow WebSocket++ to queue additional incoming connections. - * Setting it higher may prevent failed connections at high connection rates - * but may cause additional latency. - * - * For this value to take effect you may need to adjust operating system - * settings. - * - * New values affect future calls to listen only. - * - * The default value is specified as *::asio::socket_base::max_connections - * which uses the operating system defined maximum queue length. Your OS - * may restrict or silently lower this value. A value of zero may cause - * all connections to be rejected. - * - * @since 0.3.0 - * - * @param backlog The maximum length of the queue of pending connections - */ - void set_listen_backlog(int backlog) { - m_listen_backlog = backlog; - } - - /// Sets whether to use the SO_REUSEADDR flag when opening listening sockets - /** - * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What - * this flag does depends on your operating system. - * - * Please consult operating system documentation for more details. There - * may be security consequences to enabling this option. - * - * New values affect future calls to listen only so set this value prior to - * calling listen. - * - * The default is false. - * - * @since 0.3.0 - * - * @param value Whether or not to use the SO_REUSEADDR option - */ - void set_reuse_addr(bool value) { - m_reuse_addr = value; - } - - /// Retrieve a reference to the endpoint's io_service - /** - * The io_service may be an internal or external one. This may be used to - * call methods of the io_service that are not explicitly wrapped by the - * endpoint. - * - * This method is only valid after the endpoint has been initialized with - * `init_asio`. No error will be returned if it isn't. - * - * @return A reference to the endpoint's io_service - */ - lib::asio::io_service & get_io_service() { - return *m_io_service; - } - - /// Get local TCP endpoint - /** - * Extracts the local endpoint from the acceptor. This represents the - * address that WebSocket++ is listening on. - * - * Sets a bad_descriptor error if the acceptor is not currently listening - * or otherwise unavailable. - * - * @since 0.7.0 - * - * @param ec Set to indicate what error occurred, if any. - * @return The local endpoint - */ - lib::asio::ip::tcp::endpoint get_local_endpoint(lib::asio::error_code & ec) { - if (m_acceptor) { - return m_acceptor->local_endpoint(ec); - } else { - ec = lib::asio::error::make_error_code(lib::asio::error::bad_descriptor); - return lib::asio::ip::tcp::endpoint(); - } - } - - /// Set up endpoint for listening manually (exception free) - /** - * Bind the internal acceptor using the specified settings. The endpoint - * must have been initialized by calling init_asio before listening. - * - * @param ep An endpoint to read settings from - * @param ec Set to indicate what error occurred, if any. - */ - void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec) - { - if (m_state != READY) { - m_elog->write(log::elevel::library, - "asio::listen called from the wrong state"); - using websocketpp::error::make_error_code; - ec = make_error_code(websocketpp::error::invalid_state); - return; - } - - m_alog->write(log::alevel::devel,"asio::listen"); - - lib::asio::error_code bec; - - m_acceptor->open(ep.protocol(),bec); - if (bec) {ec = clean_up_listen_after_error(bec);return;} - - m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec); - if (bec) {ec = clean_up_listen_after_error(bec);return;} - - // if a TCP pre-bind handler is present, run it - if (m_tcp_pre_bind_handler) { - ec = m_tcp_pre_bind_handler(m_acceptor); - if (ec) { - ec = clean_up_listen_after_error(ec); - return; - } - } - - m_acceptor->bind(ep,bec); - if (bec) {ec = clean_up_listen_after_error(bec);return;} - - m_acceptor->listen(m_listen_backlog,bec); - if (bec) {ec = clean_up_listen_after_error(bec);return;} - - // Success - m_state = LISTENING; - ec = lib::error_code(); - } - - - - /// Set up endpoint for listening manually - /** - * Bind the internal acceptor using the settings specified by the endpoint e - * - * @param ep An endpoint to read settings from - */ - void listen(lib::asio::ip::tcp::endpoint const & ep) { - lib::error_code ec; - listen(ep,ec); - if (ec) { throw exception(ec); } - } - - /// Set up endpoint for listening with protocol and port (exception free) - /** - * Bind the internal acceptor using the given internet protocol and port. - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * Common options include: - * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() - * - IPv4 only: lib::asio::ip::tcp::v4() - * - * @param internet_protocol The internet protocol to use. - * @param port The port to listen on. - * @param ec Set to indicate what error occurred, if any. - */ - template - void listen(InternetProtocol const & internet_protocol, uint16_t port, - lib::error_code & ec) - { - lib::asio::ip::tcp::endpoint ep(internet_protocol, port); - listen(ep,ec); - } - - /// Set up endpoint for listening with protocol and port - /** - * Bind the internal acceptor using the given internet protocol and port. - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * Common options include: - * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() - * - IPv4 only: lib::asio::ip::tcp::v4() - * - * @param internet_protocol The internet protocol to use. - * @param port The port to listen on. - */ - template - void listen(InternetProtocol const & internet_protocol, uint16_t port) - { - lib::asio::ip::tcp::endpoint ep(internet_protocol, port); - listen(ep); - } - - /// Set up endpoint for listening on a port (exception free) - /** - * Bind the internal acceptor using the given port. The IPv6 protocol with - * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use - * the overload that allows specifying the protocol explicitly. - * - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * @param port The port to listen on. - * @param ec Set to indicate what error occurred, if any. - */ - void listen(uint16_t port, lib::error_code & ec) { - listen(lib::asio::ip::tcp::v6(), port, ec); - } - - /// Set up endpoint for listening on a port - /** - * Bind the internal acceptor using the given port. The IPv6 protocol with - * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use - * the overload that allows specifying the protocol explicitly. - * - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * @param port The port to listen on. - * @param ec Set to indicate what error occurred, if any. - */ - void listen(uint16_t port) { - listen(lib::asio::ip::tcp::v6(), port); - } - - /// Set up endpoint for listening on a host and service (exception free) - /** - * Bind the internal acceptor using the given host and service. More details - * about what host and service can be are available in the Asio - * documentation for ip::basic_resolver_query::basic_resolver_query's - * constructors. - * - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * @param host A string identifying a location. May be a descriptive name or - * a numeric address string. - * @param service A string identifying the requested service. This may be a - * descriptive name or a numeric string corresponding to a port number. - * @param ec Set to indicate what error occurred, if any. - */ - void listen(std::string const & host, std::string const & service, - lib::error_code & ec) - { - using lib::asio::ip::tcp; - tcp::resolver r(*m_io_service); - tcp::resolver::query query(host, service); - tcp::resolver::iterator endpoint_iterator = r.resolve(query); - tcp::resolver::iterator end; - if (endpoint_iterator == end) { - m_elog->write(log::elevel::library, - "asio::listen could not resolve the supplied host or service"); - ec = make_error_code(error::invalid_host_service); - return; - } - listen(*endpoint_iterator,ec); - } - - /// Set up endpoint for listening on a host and service - /** - * Bind the internal acceptor using the given host and service. More details - * about what host and service can be are available in the Asio - * documentation for ip::basic_resolver_query::basic_resolver_query's - * constructors. - * - * The endpoint must have been initialized by calling init_asio before - * listening. - * - * @param host A string identifying a location. May be a descriptive name or - * a numeric address string. - * @param service A string identifying the requested service. This may be a - * descriptive name or a numeric string corresponding to a port number. - * @param ec Set to indicate what error occurred, if any. - */ - void listen(std::string const & host, std::string const & service) - { - lib::error_code ec; - listen(host,service,ec); - if (ec) { throw exception(ec); } - } - - /// Stop listening (exception free) - /** - * Stop listening and accepting new connections. This will not end any - * existing connections. - * - * @since 0.3.0-alpha4 - * @param ec A status code indicating an error, if any. - */ - void stop_listening(lib::error_code & ec) { - if (m_state != LISTENING) { - m_elog->write(log::elevel::library, - "asio::listen called from the wrong state"); - using websocketpp::error::make_error_code; - ec = make_error_code(websocketpp::error::invalid_state); - return; - } - - m_acceptor->close(); - m_state = READY; - ec = lib::error_code(); - } - - /// Stop listening - /** - * Stop listening and accepting new connections. This will not end any - * existing connections. - * - * @since 0.3.0-alpha4 - */ - void stop_listening() { - lib::error_code ec; - stop_listening(ec); - if (ec) { throw exception(ec); } - } - - /// Check if the endpoint is listening - /** - * @return Whether or not the endpoint is listening. - */ - bool is_listening() const { - return (m_state == LISTENING); - } - - /// wraps the run method of the internal io_service object - std::size_t run() { - return m_io_service->run(); - } - - /// wraps the run_one method of the internal io_service object - /** - * @since 0.3.0-alpha4 - */ - std::size_t run_one() { - return m_io_service->run_one(); - } - - /// wraps the stop method of the internal io_service object - void stop() { - m_io_service->stop(); - } - - /// wraps the poll method of the internal io_service object - std::size_t poll() { - return m_io_service->poll(); - } - - /// wraps the poll_one method of the internal io_service object - std::size_t poll_one() { - return m_io_service->poll_one(); - } - - /// wraps the reset method of the internal io_service object - void reset() { - m_io_service->reset(); - } - - /// wraps the stopped method of the internal io_service object - bool stopped() const { - return m_io_service->stopped(); - } - - /// Marks the endpoint as perpetual, stopping it from exiting when empty - /** - * Marks the endpoint as perpetual. Perpetual endpoints will not - * automatically exit when they run out of connections to process. To stop - * a perpetual endpoint call `end_perpetual`. - * - * An endpoint may be marked perpetual at any time by any thread. It must be - * called either before the endpoint has run out of work or before it was - * started - * - * @since 0.3.0 - */ - void start_perpetual() { - m_work.reset(new lib::asio::io_service::work(*m_io_service)); - } - - /// Clears the endpoint's perpetual flag, allowing it to exit when empty - /** - * Clears the endpoint's perpetual flag. This will cause the endpoint's run - * method to exit normally when it runs out of connections. If there are - * currently active connections it will not end until they are complete. - * - * @since 0.3.0 - */ - void stop_perpetual() { - m_work.reset(); - } - - /// Call back a function after a period of time. - /** - * Sets a timer that calls back a function after the specified period of - * milliseconds. Returns a handle that can be used to cancel the timer. - * A cancelled timer will return the error code error::operation_aborted - * A timer that expired will return no error. - * - * @param duration Length of time to wait in milliseconds - * @param callback The function to call back when the timer has expired - * @return A handle that can be used to cancel the timer if it is no longer - * needed. - */ - timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer = lib::make_shared( - *m_io_service, - lib::asio::milliseconds(duration) - ); - - new_timer->async_wait( - lib::bind( - &type::handle_timer, - this, - new_timer, - callback, - lib::placeholders::_1 - ) - ); - - return new_timer; - } - - /// Timer handler - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * @param t Pointer to the timer in question - * @param callback The function to call back - * @param ec A status code indicating an error, if any. - */ - void handle_timer(timer_ptr, timer_handler callback, - lib::asio::error_code const & ec) - { - if (ec) { - if (ec == lib::asio::error::operation_aborted) { - callback(make_error_code(transport::error::operation_aborted)); - } else { - m_elog->write(log::elevel::info, - "asio handle_timer error: "+ec.message()); - log_err(log::elevel::info,"asio handle_timer",ec); - callback(socket_con_type::translate_ec(ec)); - } - } else { - callback(lib::error_code()); - } - } - - /// Accept the next connection attempt and assign it to con (exception free) - /** - * @param tcon The connection to accept into. - * @param callback The function to call when the operation is complete. - * @param ec A status code indicating an error, if any. - */ - void async_accept(transport_con_ptr tcon, accept_handler callback, - lib::error_code & ec) - { - if (m_state != LISTENING || !m_acceptor) { - using websocketpp::error::make_error_code; - ec = make_error_code(websocketpp::error::async_accept_not_listening); - return; - } - - m_alog->write(log::alevel::devel, "asio::async_accept"); - - if (config::enable_multithreading) { - m_acceptor->async_accept( - tcon->get_raw_socket(), - tcon->get_strand()->wrap(lib::bind( - &type::handle_accept, - this, - callback, - lib::placeholders::_1 - )) - ); - } else { - m_acceptor->async_accept( - tcon->get_raw_socket(), - lib::bind( - &type::handle_accept, - this, - callback, - lib::placeholders::_1 - ) - ); - } - } - - /// Accept the next connection attempt and assign it to con. - /** - * @param tcon The connection to accept into. - * @param callback The function to call when the operation is complete. - */ - void async_accept(transport_con_ptr tcon, accept_handler callback) { - lib::error_code ec; - async_accept(tcon,callback,ec); - if (ec) { throw exception(ec); } - } -protected: - /// Initialize logging - /** - * The loggers are located in the main endpoint class. As such, the - * transport doesn't have direct access to them. This method is called - * by the endpoint constructor to allow shared logging from the transport - * component. These are raw pointers to member variables of the endpoint. - * In particular, they cannot be used in the transport constructor as they - * haven't been constructed yet, and cannot be used in the transport - * destructor as they will have been destroyed by then. - */ - void init_logging(const lib::shared_ptr& a, const lib::shared_ptr& e) { - m_alog = a; - m_elog = e; - } - - void handle_accept(accept_handler callback, lib::asio::error_code const & - asio_ec) - { - lib::error_code ret_ec; - - m_alog->write(log::alevel::devel, "asio::handle_accept"); - - if (asio_ec) { - if (asio_ec == lib::asio::errc::operation_canceled) { - ret_ec = make_error_code(websocketpp::error::operation_canceled); - } else { - log_err(log::elevel::info,"asio handle_accept",asio_ec); - ret_ec = socket_con_type::translate_ec(asio_ec); - } - } - - callback(ret_ec); - } - - /// Initiate a new connection - // TODO: there have to be some more failure conditions here - void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { - using namespace lib::asio::ip; - - // Create a resolver - if (!m_resolver) { - m_resolver.reset(new lib::asio::ip::tcp::resolver(*m_io_service)); - } - - tcon->set_uri(u); - - std::string proxy = tcon->get_proxy(); - std::string host; - std::string port; - - if (proxy.empty()) { - host = u->get_host(); - port = u->get_port_str(); - } else { - lib::error_code ec; - - uri_ptr pu = lib::make_shared(proxy); - - if (!pu->get_valid()) { - cb(make_error_code(error::proxy_invalid)); - return; - } - - ec = tcon->proxy_init(u->get_authority()); - if (ec) { - cb(ec); - return; - } - - host = pu->get_host(); - port = pu->get_port_str(); - } - - tcp::resolver::query query(host,port); - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel, - "starting async DNS resolve for "+host+":"+port); - } - - timer_ptr dns_timer; - - dns_timer = tcon->set_timer( - config::timeout_dns_resolve, - lib::bind( - &type::handle_resolve_timeout, - this, - dns_timer, - cb, - lib::placeholders::_1 - ) - ); - - if (config::enable_multithreading) { - m_resolver->async_resolve( - query, - tcon->get_strand()->wrap(lib::bind( - &type::handle_resolve, - this, - tcon, - dns_timer, - cb, - lib::placeholders::_1, - lib::placeholders::_2 - )) - ); - } else { - m_resolver->async_resolve( - query, - lib::bind( - &type::handle_resolve, - this, - tcon, - dns_timer, - cb, - lib::placeholders::_1, - lib::placeholders::_2 - ) - ); - } - } - - /// DNS resolution timeout handler - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * @param dns_timer Pointer to the timer in question - * @param callback The function to call back - * @param ec A status code indicating an error, if any. - */ - void handle_resolve_timeout(timer_ptr, connect_handler callback, - lib::error_code const & ec) - { - lib::error_code ret_ec; - - if (ec) { - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel, - "asio handle_resolve_timeout timer cancelled"); - return; - } - - log_err(log::elevel::devel,"asio handle_resolve_timeout",ec); - ret_ec = ec; - } else { - ret_ec = make_error_code(transport::error::timeout); - } - - m_alog->write(log::alevel::devel,"DNS resolution timed out"); - m_resolver->cancel(); - callback(ret_ec); - } - - void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer, - connect_handler callback, lib::asio::error_code const & ec, - lib::asio::ip::tcp::resolver::iterator iterator) - { - if (ec == lib::asio::error::operation_aborted || - lib::asio::is_neg(dns_timer->expires_from_now())) - { - m_alog->write(log::alevel::devel,"async_resolve cancelled"); - return; - } - - dns_timer->cancel(); - - if (ec) { - log_err(log::elevel::info,"asio async_resolve",ec); - callback(socket_con_type::translate_ec(ec)); - return; - } - - if (m_alog->static_test(log::alevel::devel)) { - std::stringstream s; - s << "Async DNS resolve successful. Results: "; - - lib::asio::ip::tcp::resolver::iterator it, end; - for (it = iterator; it != end; ++it) { - s << (*it).endpoint() << " "; - } - - m_alog->write(log::alevel::devel,s.str()); - } - - m_alog->write(log::alevel::devel,"Starting async connect"); - - timer_ptr con_timer; - - con_timer = tcon->set_timer( - config::timeout_connect, - lib::bind( - &type::handle_connect_timeout, - this, - tcon, - con_timer, - callback, - lib::placeholders::_1 - ) - ); - - if (config::enable_multithreading) { - lib::asio::async_connect( - tcon->get_raw_socket(), - iterator, - tcon->get_strand()->wrap(lib::bind( - &type::handle_connect, - this, - tcon, - con_timer, - callback, - lib::placeholders::_1 - )) - ); - } else { - lib::asio::async_connect( - tcon->get_raw_socket(), - iterator, - lib::bind( - &type::handle_connect, - this, - tcon, - con_timer, - callback, - lib::placeholders::_1 - ) - ); - } - } - - /// Asio connect timeout handler - /** - * The timer pointer is included to ensure the timer isn't destroyed until - * after it has expired. - * - * @param tcon Pointer to the transport connection that is being connected - * @param con_timer Pointer to the timer in question - * @param callback The function to call back - * @param ec A status code indicating an error, if any. - */ - void handle_connect_timeout(transport_con_ptr tcon, timer_ptr, - connect_handler callback, lib::error_code const & ec) - { - lib::error_code ret_ec; - - if (ec) { - if (ec == transport::error::operation_aborted) { - m_alog->write(log::alevel::devel, - "asio handle_connect_timeout timer cancelled"); - return; - } - - log_err(log::elevel::devel,"asio handle_connect_timeout",ec); - ret_ec = ec; - } else { - ret_ec = make_error_code(transport::error::timeout); - } - - m_alog->write(log::alevel::devel,"TCP connect timed out"); - tcon->cancel_socket_checked(); - callback(ret_ec); - } - - void handle_connect(transport_con_ptr tcon, timer_ptr con_timer, - connect_handler callback, lib::asio::error_code const & ec) - { - if (ec == lib::asio::error::operation_aborted || - lib::asio::is_neg(con_timer->expires_from_now())) - { - m_alog->write(log::alevel::devel,"async_connect cancelled"); - return; - } - - con_timer->cancel(); - - if (ec) { - log_err(log::elevel::info,"asio async_connect",ec); - callback(socket_con_type::translate_ec(ec)); - return; - } - - if (m_alog->static_test(log::alevel::devel)) { - m_alog->write(log::alevel::devel, - "Async connect to "+tcon->get_remote_endpoint()+" successful."); - } - - callback(lib::error_code()); - } - - /// Initialize a connection - /** - * init is called by an endpoint once for each newly created connection. - * It's purpose is to give the transport policy the chance to perform any - * transport specific initialization that couldn't be done via the default - * constructor. - * - * @param tcon A pointer to the transport portion of the connection. - * - * @return A status code indicating the success or failure of the operation - */ - lib::error_code init(transport_con_ptr tcon) { - m_alog->write(log::alevel::devel, "transport::asio::init"); - - // Initialize the connection socket component - socket_type::init(lib::static_pointer_cast(tcon)); - - lib::error_code ec; - - ec = tcon->init_asio(m_io_service); - if (ec) {return ec;} - - tcon->set_tcp_pre_init_handler(m_tcp_pre_init_handler); - tcon->set_tcp_post_init_handler(m_tcp_post_init_handler); - - return lib::error_code(); - } -private: - /// Convenience method for logging the code and message for an error_code - template - void log_err(log::level l, char const * msg, error_type const & ec) { - std::stringstream s; - s << msg << " error: " << ec << " (" << ec.message() << ")"; - m_elog->write(l,s.str()); - } - - /// Helper for cleaning up in the listen method after an error - template - lib::error_code clean_up_listen_after_error(error_type const & ec) { - if (m_acceptor->is_open()) { - m_acceptor->close(); - } - log_err(log::elevel::info,"asio listen",ec); - return socket_con_type::translate_ec(ec); - } - - enum state { - UNINITIALIZED = 0, - READY = 1, - LISTENING = 2 - }; - - // Handlers - tcp_pre_bind_handler m_tcp_pre_bind_handler; - tcp_init_handler m_tcp_pre_init_handler; - tcp_init_handler m_tcp_post_init_handler; - - // Network Resources - io_service_ptr m_io_service; - bool m_external_io_service; - acceptor_ptr m_acceptor; - resolver_ptr m_resolver; - work_ptr m_work; - - // Network constants - int m_listen_backlog; - bool m_reuse_addr; - - lib::shared_ptr m_elog; - lib::shared_ptr m_alog; - - // Transport state - state m_state; -}; - -} // namespace asio -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP +/* + * 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_HPP +#define WEBSOCKETPP_TRANSPORT_ASIO_HPP + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace asio { + +/// Asio based endpoint transport component +/** + * transport::asio::endpoint implements an endpoint transport component using + * Asio. + */ +template +class endpoint : public config::socket_type { +public: + /// Type of this endpoint transport component + typedef endpoint type; + + /// Type of the concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of the socket policy + typedef typename config::socket_type socket_type; + /// Type of the error logging policy + typedef typename config::elog_type elog_type; + /// Type of the access logging policy + typedef typename config::alog_type alog_type; + + /// Type of the socket connection component + typedef typename socket_type::socket_con_type socket_con_type; + /// Type of a shared pointer to the socket connection component + typedef typename socket_con_type::ptr socket_con_ptr; + + /// Type of the connection transport component associated with this + /// endpoint transport component + typedef asio::connection transport_con_type; + /// Type of a shared pointer to the connection transport component + /// associated with this endpoint transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + /// Type of a pointer to the ASIO io_service being used + typedef lib::asio::io_service * io_service_ptr; + /// Type of a shared pointer to the acceptor being used + typedef lib::shared_ptr acceptor_ptr; + /// Type of a shared pointer to the resolver being used + typedef lib::shared_ptr resolver_ptr; + /// Type of timer handle + typedef lib::shared_ptr timer_ptr; + /// Type of a shared pointer to an io_service work object + typedef lib::shared_ptr work_ptr; + + /// Type of socket pre-bind handler + typedef lib::function tcp_pre_bind_handler; + + // generate and manage our own io_service + explicit endpoint() + : m_io_service(NULL) + , m_external_io_service(false) + , m_listen_backlog(lib::asio::socket_base::max_connections) + , m_reuse_addr(false) + , m_state(UNINITIALIZED) + { + //std::cout << "transport::asio::endpoint constructor" << std::endl; + } + + ~endpoint() { + // clean up our io_service if we were initialized with an internal one. + + // Explicitly destroy local objects + m_acceptor.reset(); + m_resolver.reset(); + m_work.reset(); + if (m_state != UNINITIALIZED && !m_external_io_service) { + delete m_io_service; + } + } + + /// transport::asio objects are moveable but not copyable or assignable. + /// The following code sets this situation up based on whether or not we + /// have C++11 support or not +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + endpoint(const endpoint & src) = delete; + endpoint& operator= (const endpoint & rhs) = delete; +#else +private: + endpoint(const endpoint & src); + endpoint & operator= (const endpoint & rhs); +public: +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + endpoint (endpoint && src) + : config::socket_type(std::move(src)) + , m_tcp_pre_init_handler(src.m_tcp_pre_init_handler) + , m_tcp_post_init_handler(src.m_tcp_post_init_handler) + , m_io_service(src.m_io_service) + , m_external_io_service(src.m_external_io_service) + , m_acceptor(src.m_acceptor) + , m_listen_backlog(lib::asio::socket_base::max_connections) + , m_reuse_addr(src.m_reuse_addr) + , m_elog(src.m_elog) + , m_alog(src.m_alog) + , m_state(src.m_state) + { + src.m_io_service = NULL; + src.m_external_io_service = false; + src.m_acceptor = NULL; + src.m_state = UNINITIALIZED; + } + + /*endpoint & operator= (const endpoint && rhs) { + if (this != &rhs) { + m_io_service = rhs.m_io_service; + m_external_io_service = rhs.m_external_io_service; + m_acceptor = rhs.m_acceptor; + m_listen_backlog = rhs.m_listen_backlog; + m_reuse_addr = rhs.m_reuse_addr; + m_state = rhs.m_state; + + rhs.m_io_service = NULL; + rhs.m_external_io_service = false; + rhs.m_acceptor = NULL; + rhs.m_listen_backlog = lib::asio::socket_base::max_connections; + rhs.m_state = UNINITIALIZED; + + // TODO: this needs to be updated + } + return *this; + }*/ +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + + /// Return whether or not the endpoint produces secure connections. + bool is_secure() const { + return socket_type::is_secure(); + } + + /// initialize asio transport with external io_service (exception free) + /** + * Initialize the ASIO transport policy for this endpoint using the provided + * io_service object. asio_init must be called exactly once on any endpoint + * that uses transport::asio before it can be used. + * + * @param ptr A pointer to the io_service to use for asio events + * @param ec Set to indicate what error occurred, if any. + */ + void init_asio(io_service_ptr ptr, lib::error_code & ec) { + if (m_state != UNINITIALIZED) { + m_elog->write(log::elevel::library, + "asio::init_asio called from the wrong state"); + using websocketpp::error::make_error_code; + ec = make_error_code(websocketpp::error::invalid_state); + return; + } + + m_alog->write(log::alevel::devel,"asio::init_asio"); + + m_io_service = ptr; + m_external_io_service = true; + m_acceptor.reset(new lib::asio::ip::tcp::acceptor(*m_io_service)); + + m_state = READY; + ec = lib::error_code(); + } + + /// initialize asio transport with external io_service + /** + * Initialize the ASIO transport policy for this endpoint using the provided + * io_service object. asio_init must be called exactly once on any endpoint + * that uses transport::asio before it can be used. + * + * @param ptr A pointer to the io_service to use for asio events + */ + void init_asio(io_service_ptr ptr) { + lib::error_code ec; + init_asio(ptr,ec); + if (ec) { throw exception(ec); } + } + + /// Initialize asio transport with internal io_service (exception free) + /** + * This method of initialization will allocate and use an internally managed + * io_service. + * + * @see init_asio(io_service_ptr ptr) + * + * @param ec Set to indicate what error occurred, if any. + */ + void init_asio(lib::error_code & ec) { + // Use a smart pointer until the call is successful and ownership has + // successfully been taken. Use unique_ptr when available. + // TODO: remove the use of auto_ptr when C++98/03 support is no longer + // necessary. +#ifdef _WEBSOCKETPP_CPP11_MEMORY_ + lib::unique_ptr service(new lib::asio::io_service()); +#else + lib::auto_ptr service(new lib::asio::io_service()); +#endif + init_asio(service.get(), ec); + if( !ec ) service.release(); // Call was successful, transfer ownership + m_external_io_service = false; + } + + /// Initialize asio transport with internal io_service + /** + * This method of initialization will allocate and use an internally managed + * io_service. + * + * @see init_asio(io_service_ptr ptr) + */ + void init_asio() { + // Use a smart pointer until the call is successful and ownership has + // successfully been taken. Use unique_ptr when available. + // TODO: remove the use of auto_ptr when C++98/03 support is no longer + // necessary. +#ifdef _WEBSOCKETPP_CPP11_MEMORY_ + lib::unique_ptr service(new lib::asio::io_service()); +#else + lib::auto_ptr service(new lib::asio::io_service()); +#endif + init_asio( service.get() ); + // If control got this far without an exception, then ownership has successfully been taken + service.release(); + m_external_io_service = false; + } + + /// Sets the tcp pre bind handler + /** + * The tcp pre bind handler is called after the listen acceptor has + * been created but before the socket bind is performed. + * + * @since 0.8.0 + * + * @param h The handler to call on tcp pre bind init. + */ + void set_tcp_pre_bind_handler(tcp_pre_bind_handler h) { + m_tcp_pre_bind_handler = h; + } + + /// Sets the tcp pre init handler + /** + * The tcp pre init handler is called after the raw tcp connection has been + * established but before any additional wrappers (proxy connects, TLS + * handshakes, etc) have been performed. + * + * @since 0.3.0 + * + * @param h The handler to call on tcp pre init. + */ + void set_tcp_pre_init_handler(tcp_init_handler h) { + m_tcp_pre_init_handler = h; + } + + /// Sets the tcp pre init handler (deprecated) + /** + * The tcp pre init handler is called after the raw tcp connection has been + * established but before any additional wrappers (proxy connects, TLS + * handshakes, etc) have been performed. + * + * @deprecated Use set_tcp_pre_init_handler instead + * + * @param h The handler to call on tcp pre init. + */ + void set_tcp_init_handler(tcp_init_handler h) { + set_tcp_pre_init_handler(h); + } + + /// Sets the tcp post init handler + /** + * The tcp post init handler is called after the tcp connection has been + * established and all additional wrappers (proxy connects, TLS handshakes, + * etc have been performed. This is fired before any bytes are read or any + * WebSocket specific handshake logic has been performed. + * + * @since 0.3.0 + * + * @param h The handler to call on tcp post init. + */ + void set_tcp_post_init_handler(tcp_init_handler h) { + m_tcp_post_init_handler = h; + } + + /// Sets the maximum length of the queue of pending connections. + /** + * Sets the maximum length of the queue of pending connections. Increasing + * this will allow WebSocket++ to queue additional incoming connections. + * Setting it higher may prevent failed connections at high connection rates + * but may cause additional latency. + * + * For this value to take effect you may need to adjust operating system + * settings. + * + * New values affect future calls to listen only. + * + * The default value is specified as *::asio::socket_base::max_connections + * which uses the operating system defined maximum queue length. Your OS + * may restrict or silently lower this value. A value of zero may cause + * all connections to be rejected. + * + * @since 0.3.0 + * + * @param backlog The maximum length of the queue of pending connections + */ + void set_listen_backlog(int backlog) { + m_listen_backlog = backlog; + } + + /// Sets whether to use the SO_REUSEADDR flag when opening listening sockets + /** + * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What + * this flag does depends on your operating system. + * + * Please consult operating system documentation for more details. There + * may be security consequences to enabling this option. + * + * New values affect future calls to listen only so set this value prior to + * calling listen. + * + * The default is false. + * + * @since 0.3.0 + * + * @param value Whether or not to use the SO_REUSEADDR option + */ + void set_reuse_addr(bool value) { + m_reuse_addr = value; + } + + /// Retrieve a reference to the endpoint's io_service + /** + * The io_service may be an internal or external one. This may be used to + * call methods of the io_service that are not explicitly wrapped by the + * endpoint. + * + * This method is only valid after the endpoint has been initialized with + * `init_asio`. No error will be returned if it isn't. + * + * @return A reference to the endpoint's io_service + */ + lib::asio::io_service & get_io_service() { + return *m_io_service; + } + + /// Get local TCP endpoint + /** + * Extracts the local endpoint from the acceptor. This represents the + * address that WebSocket++ is listening on. + * + * Sets a bad_descriptor error if the acceptor is not currently listening + * or otherwise unavailable. + * + * @since 0.7.0 + * + * @param ec Set to indicate what error occurred, if any. + * @return The local endpoint + */ + lib::asio::ip::tcp::endpoint get_local_endpoint(lib::asio::error_code & ec) { + if (m_acceptor) { + return m_acceptor->local_endpoint(ec); + } else { + ec = lib::asio::error::make_error_code(lib::asio::error::bad_descriptor); + return lib::asio::ip::tcp::endpoint(); + } + } + + /// Set up endpoint for listening manually (exception free) + /** + * Bind the internal acceptor using the specified settings. The endpoint + * must have been initialized by calling init_asio before listening. + * + * @param ep An endpoint to read settings from + * @param ec Set to indicate what error occurred, if any. + */ + void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec) + { + if (m_state != READY) { + m_elog->write(log::elevel::library, + "asio::listen called from the wrong state"); + using websocketpp::error::make_error_code; + ec = make_error_code(websocketpp::error::invalid_state); + return; + } + + m_alog->write(log::alevel::devel,"asio::listen"); + + lib::asio::error_code bec; + + m_acceptor->open(ep.protocol(),bec); + if (bec) {ec = clean_up_listen_after_error(bec);return;} + + m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec); + if (bec) {ec = clean_up_listen_after_error(bec);return;} + + // if a TCP pre-bind handler is present, run it + if (m_tcp_pre_bind_handler) { + ec = m_tcp_pre_bind_handler(m_acceptor); + if (ec) { + ec = clean_up_listen_after_error(ec); + return; + } + } + + m_acceptor->bind(ep,bec); + if (bec) {ec = clean_up_listen_after_error(bec);return;} + + m_acceptor->listen(m_listen_backlog,bec); + if (bec) {ec = clean_up_listen_after_error(bec);return;} + + // Success + m_state = LISTENING; + ec = lib::error_code(); + } + + + + /// Set up endpoint for listening manually + /** + * Bind the internal acceptor using the settings specified by the endpoint e + * + * @param ep An endpoint to read settings from + */ + void listen(lib::asio::ip::tcp::endpoint const & ep) { + lib::error_code ec; + listen(ep,ec); + if (ec) { throw exception(ec); } + } + + /// Set up endpoint for listening with protocol and port (exception free) + /** + * Bind the internal acceptor using the given internet protocol and port. + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * Common options include: + * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() + * - IPv4 only: lib::asio::ip::tcp::v4() + * + * @param internet_protocol The internet protocol to use. + * @param port The port to listen on. + * @param ec Set to indicate what error occurred, if any. + */ + template + void listen(InternetProtocol const & internet_protocol, uint16_t port, + lib::error_code & ec) + { + lib::asio::ip::tcp::endpoint ep(internet_protocol, port); + listen(ep,ec); + } + + /// Set up endpoint for listening with protocol and port + /** + * Bind the internal acceptor using the given internet protocol and port. + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * Common options include: + * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() + * - IPv4 only: lib::asio::ip::tcp::v4() + * + * @param internet_protocol The internet protocol to use. + * @param port The port to listen on. + */ + template + void listen(InternetProtocol const & internet_protocol, uint16_t port) + { + lib::asio::ip::tcp::endpoint ep(internet_protocol, port); + listen(ep); + } + + /// Set up endpoint for listening on a port (exception free) + /** + * Bind the internal acceptor using the given port. The IPv6 protocol with + * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use + * the overload that allows specifying the protocol explicitly. + * + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * @param port The port to listen on. + * @param ec Set to indicate what error occurred, if any. + */ + void listen(uint16_t port, lib::error_code & ec) { + listen(lib::asio::ip::tcp::v6(), port, ec); + } + + /// Set up endpoint for listening on a port + /** + * Bind the internal acceptor using the given port. The IPv6 protocol with + * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use + * the overload that allows specifying the protocol explicitly. + * + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * @param port The port to listen on. + * @param ec Set to indicate what error occurred, if any. + */ + void listen(uint16_t port) { + listen(lib::asio::ip::tcp::v6(), port); + } + + /// Set up endpoint for listening on a host and service (exception free) + /** + * Bind the internal acceptor using the given host and service. More details + * about what host and service can be are available in the Asio + * documentation for ip::basic_resolver_query::basic_resolver_query's + * constructors. + * + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. + * @param ec Set to indicate what error occurred, if any. + */ + void listen(std::string const & host, std::string const & service, + lib::error_code & ec) + { + using lib::asio::ip::tcp; + tcp::resolver r(*m_io_service); + tcp::resolver::query query(host, service); + tcp::resolver::iterator endpoint_iterator = r.resolve(query); + tcp::resolver::iterator end; + if (endpoint_iterator == end) { + m_elog->write(log::elevel::library, + "asio::listen could not resolve the supplied host or service"); + ec = make_error_code(error::invalid_host_service); + return; + } + listen(*endpoint_iterator,ec); + } + + /// Set up endpoint for listening on a host and service + /** + * Bind the internal acceptor using the given host and service. More details + * about what host and service can be are available in the Asio + * documentation for ip::basic_resolver_query::basic_resolver_query's + * constructors. + * + * The endpoint must have been initialized by calling init_asio before + * listening. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. + * @param ec Set to indicate what error occurred, if any. + */ + void listen(std::string const & host, std::string const & service) + { + lib::error_code ec; + listen(host,service,ec); + if (ec) { throw exception(ec); } + } + + /// Stop listening (exception free) + /** + * Stop listening and accepting new connections. This will not end any + * existing connections. + * + * @since 0.3.0-alpha4 + * @param ec A status code indicating an error, if any. + */ + void stop_listening(lib::error_code & ec) { + if (m_state != LISTENING) { + m_elog->write(log::elevel::library, + "asio::listen called from the wrong state"); + using websocketpp::error::make_error_code; + ec = make_error_code(websocketpp::error::invalid_state); + return; + } + + m_acceptor->close(); + m_state = READY; + ec = lib::error_code(); + } + + /// Stop listening + /** + * Stop listening and accepting new connections. This will not end any + * existing connections. + * + * @since 0.3.0-alpha4 + */ + void stop_listening() { + lib::error_code ec; + stop_listening(ec); + if (ec) { throw exception(ec); } + } + + /// Check if the endpoint is listening + /** + * @return Whether or not the endpoint is listening. + */ + bool is_listening() const { + return (m_state == LISTENING); + } + + /// wraps the run method of the internal io_service object + std::size_t run() { + return m_io_service->run(); + } + + /// wraps the run_one method of the internal io_service object + /** + * @since 0.3.0-alpha4 + */ + std::size_t run_one() { + return m_io_service->run_one(); + } + + /// wraps the stop method of the internal io_service object + void stop() { + m_io_service->stop(); + } + + /// wraps the poll method of the internal io_service object + std::size_t poll() { + return m_io_service->poll(); + } + + /// wraps the poll_one method of the internal io_service object + std::size_t poll_one() { + return m_io_service->poll_one(); + } + + /// wraps the reset method of the internal io_service object + void reset() { + m_io_service->reset(); + } + + /// wraps the stopped method of the internal io_service object + bool stopped() const { + return m_io_service->stopped(); + } + + /// Marks the endpoint as perpetual, stopping it from exiting when empty + /** + * Marks the endpoint as perpetual. Perpetual endpoints will not + * automatically exit when they run out of connections to process. To stop + * a perpetual endpoint call `end_perpetual`. + * + * An endpoint may be marked perpetual at any time by any thread. It must be + * called either before the endpoint has run out of work or before it was + * started + * + * @since 0.3.0 + */ + void start_perpetual() { + m_work.reset(new lib::asio::io_service::work(*m_io_service)); + } + + /// Clears the endpoint's perpetual flag, allowing it to exit when empty + /** + * Clears the endpoint's perpetual flag. This will cause the endpoint's run + * method to exit normally when it runs out of connections. If there are + * currently active connections it will not end until they are complete. + * + * @since 0.3.0 + */ + void stop_perpetual() { + m_work.reset(); + } + + /// Call back a function after a period of time. + /** + * Sets a timer that calls back a function after the specified period of + * milliseconds. Returns a handle that can be used to cancel the timer. + * A cancelled timer will return the error code error::operation_aborted + * A timer that expired will return no error. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long duration, timer_handler callback) { + timer_ptr new_timer = lib::make_shared( + *m_io_service, + lib::asio::milliseconds(duration) + ); + + new_timer->async_wait( + lib::bind( + &type::handle_timer, + this, + new_timer, + callback, + lib::placeholders::_1 + ) + ); + + return new_timer; + } + + /// Timer handler + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param t Pointer to the timer in question + * @param callback The function to call back + * @param ec A status code indicating an error, if any. + */ + void handle_timer(timer_ptr, timer_handler callback, + lib::asio::error_code const & ec) + { + if (ec) { + if (ec == lib::asio::error::operation_aborted) { + callback(make_error_code(transport::error::operation_aborted)); + } else { + m_elog->write(log::elevel::info, + "asio handle_timer error: "+ec.message()); + log_err(log::elevel::info,"asio handle_timer",ec); + callback(socket_con_type::translate_ec(ec)); + } + } else { + callback(lib::error_code()); + } + } + + /// Accept the next connection attempt and assign it to con (exception free) + /** + * @param tcon The connection to accept into. + * @param callback The function to call when the operation is complete. + * @param ec A status code indicating an error, if any. + */ + void async_accept(transport_con_ptr tcon, accept_handler callback, + lib::error_code & ec) + { + if (m_state != LISTENING || !m_acceptor) { + using websocketpp::error::make_error_code; + ec = make_error_code(websocketpp::error::async_accept_not_listening); + return; + } + + m_alog->write(log::alevel::devel, "asio::async_accept"); + + if (config::enable_multithreading) { + m_acceptor->async_accept( + tcon->get_raw_socket(), + tcon->get_strand()->wrap(lib::bind( + &type::handle_accept, + this, + callback, + lib::placeholders::_1 + )) + ); + } else { + m_acceptor->async_accept( + tcon->get_raw_socket(), + lib::bind( + &type::handle_accept, + this, + callback, + lib::placeholders::_1 + ) + ); + } + } + + /// Accept the next connection attempt and assign it to con. + /** + * @param tcon The connection to accept into. + * @param callback The function to call when the operation is complete. + */ + void async_accept(transport_con_ptr tcon, accept_handler callback) { + lib::error_code ec; + async_accept(tcon,callback,ec); + if (ec) { throw exception(ec); } + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + */ + void init_logging(const lib::shared_ptr& a, const lib::shared_ptr& e) { + m_alog = a; + m_elog = e; + } + + void handle_accept(accept_handler callback, lib::asio::error_code const & + asio_ec) + { + lib::error_code ret_ec; + + m_alog->write(log::alevel::devel, "asio::handle_accept"); + + if (asio_ec) { + if (asio_ec == lib::asio::errc::operation_canceled) { + ret_ec = make_error_code(websocketpp::error::operation_canceled); + } else { + log_err(log::elevel::info,"asio handle_accept",asio_ec); + ret_ec = socket_con_type::translate_ec(asio_ec); + } + } + + callback(ret_ec); + } + + /// Initiate a new connection + // TODO: there have to be some more failure conditions here + void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { + using namespace lib::asio::ip; + + // Create a resolver + if (!m_resolver) { + m_resolver.reset(new lib::asio::ip::tcp::resolver(*m_io_service)); + } + + tcon->set_uri(u); + + std::string proxy = tcon->get_proxy(); + std::string host; + std::string port; + + if (proxy.empty()) { + host = u->get_host(); + port = u->get_port_str(); + } else { + lib::error_code ec; + + uri_ptr pu = lib::make_shared(proxy); + + if (!pu->get_valid()) { + cb(make_error_code(error::proxy_invalid)); + return; + } + + ec = tcon->proxy_init(u->get_authority()); + if (ec) { + cb(ec); + return; + } + + host = pu->get_host(); + port = pu->get_port_str(); + } + + tcp::resolver::query query(host,port); + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel, + "starting async DNS resolve for "+host+":"+port); + } + + timer_ptr dns_timer; + + dns_timer = tcon->set_timer( + config::timeout_dns_resolve, + lib::bind( + &type::handle_resolve_timeout, + this, + dns_timer, + cb, + lib::placeholders::_1 + ) + ); + + if (config::enable_multithreading) { + m_resolver->async_resolve( + query, + tcon->get_strand()->wrap(lib::bind( + &type::handle_resolve, + this, + tcon, + dns_timer, + cb, + lib::placeholders::_1, + lib::placeholders::_2 + )) + ); + } else { + m_resolver->async_resolve( + query, + lib::bind( + &type::handle_resolve, + this, + tcon, + dns_timer, + cb, + lib::placeholders::_1, + lib::placeholders::_2 + ) + ); + } + } + + /// DNS resolution timeout handler + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param dns_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec A status code indicating an error, if any. + */ + void handle_resolve_timeout(timer_ptr, connect_handler callback, + lib::error_code const & ec) + { + lib::error_code ret_ec; + + if (ec) { + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel, + "asio handle_resolve_timeout timer cancelled"); + return; + } + + log_err(log::elevel::devel,"asio handle_resolve_timeout",ec); + ret_ec = ec; + } else { + ret_ec = make_error_code(transport::error::timeout); + } + + m_alog->write(log::alevel::devel,"DNS resolution timed out"); + m_resolver->cancel(); + callback(ret_ec); + } + + void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer, + connect_handler callback, lib::asio::error_code const & ec, + lib::asio::ip::tcp::resolver::iterator iterator) + { + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(dns_timer->expires_from_now())) + { + m_alog->write(log::alevel::devel,"async_resolve cancelled"); + return; + } + + dns_timer->cancel(); + + if (ec) { + log_err(log::elevel::info,"asio async_resolve",ec); + callback(socket_con_type::translate_ec(ec)); + return; + } + + if (m_alog->static_test(log::alevel::devel)) { + std::stringstream s; + s << "Async DNS resolve successful. Results: "; + + lib::asio::ip::tcp::resolver::iterator it, end; + for (it = iterator; it != end; ++it) { + s << (*it).endpoint() << " "; + } + + m_alog->write(log::alevel::devel,s.str()); + } + + m_alog->write(log::alevel::devel,"Starting async connect"); + + timer_ptr con_timer; + + con_timer = tcon->set_timer( + config::timeout_connect, + lib::bind( + &type::handle_connect_timeout, + this, + tcon, + con_timer, + callback, + lib::placeholders::_1 + ) + ); + + if (config::enable_multithreading) { + lib::asio::async_connect( + tcon->get_raw_socket(), + iterator, + tcon->get_strand()->wrap(lib::bind( + &type::handle_connect, + this, + tcon, + con_timer, + callback, + lib::placeholders::_1 + )) + ); + } else { + lib::asio::async_connect( + tcon->get_raw_socket(), + iterator, + lib::bind( + &type::handle_connect, + this, + tcon, + con_timer, + callback, + lib::placeholders::_1 + ) + ); + } + } + + /// Asio connect timeout handler + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param tcon Pointer to the transport connection that is being connected + * @param con_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec A status code indicating an error, if any. + */ + void handle_connect_timeout(transport_con_ptr tcon, timer_ptr, + connect_handler callback, lib::error_code const & ec) + { + lib::error_code ret_ec; + + if (ec) { + if (ec == transport::error::operation_aborted) { + m_alog->write(log::alevel::devel, + "asio handle_connect_timeout timer cancelled"); + return; + } + + log_err(log::elevel::devel,"asio handle_connect_timeout",ec); + ret_ec = ec; + } else { + ret_ec = make_error_code(transport::error::timeout); + } + + m_alog->write(log::alevel::devel,"TCP connect timed out"); + tcon->cancel_socket_checked(); + callback(ret_ec); + } + + void handle_connect(transport_con_ptr tcon, timer_ptr con_timer, + connect_handler callback, lib::asio::error_code const & ec) + { + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(con_timer->expires_from_now())) + { + m_alog->write(log::alevel::devel,"async_connect cancelled"); + return; + } + + con_timer->cancel(); + + if (ec) { + log_err(log::elevel::info,"asio async_connect",ec); + callback(socket_con_type::translate_ec(ec)); + return; + } + + if (m_alog->static_test(log::alevel::devel)) { + m_alog->write(log::alevel::devel, + "Async connect to "+tcon->get_remote_endpoint()+" successful."); + } + + callback(lib::error_code()); + } + + /// Initialize a connection + /** + * init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr tcon) { + m_alog->write(log::alevel::devel, "transport::asio::init"); + + // Initialize the connection socket component + socket_type::init(lib::static_pointer_cast(tcon)); + + lib::error_code ec; + + ec = tcon->init_asio(m_io_service); + if (ec) {return ec;} + + tcon->set_tcp_pre_init_handler(m_tcp_pre_init_handler); + tcon->set_tcp_post_init_handler(m_tcp_post_init_handler); + + return lib::error_code(); + } +private: + /// Convenience method for logging the code and message for an error_code + template + void log_err(log::level l, char const * msg, error_type const & ec) { + std::stringstream s; + s << msg << " error: " << ec << " (" << ec.message() << ")"; + m_elog->write(l,s.str()); + } + + /// Helper for cleaning up in the listen method after an error + template + lib::error_code clean_up_listen_after_error(error_type const & ec) { + if (m_acceptor->is_open()) { + m_acceptor->close(); + } + log_err(log::elevel::info,"asio listen",ec); + return socket_con_type::translate_ec(ec); + } + + enum state { + UNINITIALIZED = 0, + READY = 1, + LISTENING = 2 + }; + + // Handlers + tcp_pre_bind_handler m_tcp_pre_bind_handler; + tcp_init_handler m_tcp_pre_init_handler; + tcp_init_handler m_tcp_post_init_handler; + + // Network Resources + io_service_ptr m_io_service; + bool m_external_io_service; + acceptor_ptr m_acceptor; + resolver_ptr m_resolver; + work_ptr m_work; + + // Network constants + int m_listen_backlog; + bool m_reuse_addr; + + lib::shared_ptr m_elog; + lib::shared_ptr m_alog; + + // Transport state + state m_state; +}; + +} // namespace asio +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/base.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/base.hpp index 441c614..0f08f40 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/base.hpp @@ -1,159 +1,159 @@ -/* - * 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_SOCKET_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP - -#include -#include -#include -#include -#include -#include - -#include - -// Interface that sockets/security policies must implement - -/* - * Endpoint Interface - * - * bool is_secure() const; - * @return Whether or not the endpoint creates secure connections - * - * lib::error_code init(socket_con_ptr scon); - * Called by the transport after a new connection is created to initialize - * the socket component of the connection. - * @param scon Pointer to the socket component of the connection - * @return Error code (empty on success) - */ - - -// Connection -// TODO -// set_hostname(std::string hostname) -// pre_init(init_handler); -// post_init(init_handler); - -namespace websocketpp { -namespace transport { -namespace asio { -namespace socket { - -typedef lib::function shutdown_handler; - -/** - * The transport::asio::socket::* classes are a set of security/socket related - * policies and support code for the ASIO transport types. - */ - -/// Errors related to asio transport sockets -namespace error { - enum value { - /// Catch-all error for security policy errors that don't fit in other - /// categories - security = 1, - - /// Catch-all error for socket component errors that don't fit in other - /// categories - socket, - - /// A function was called in a state that it was illegal to do so. - invalid_state, - - /// The application was prompted to provide a TLS context and it was - /// empty or otherwise invalid - invalid_tls_context, - - /// TLS Handshake Timeout - tls_handshake_timeout, - - /// pass_through from underlying library - pass_through, - - /// Required tls_init handler not present - missing_tls_init_handler, - - /// TLS Handshake Failed - tls_handshake_failed, - - /// Failed to set TLS SNI hostname - tls_failed_sni_hostname - }; -} // namespace error - -/// Error category related to asio transport socket policies -class socket_category : public lib::error_category { -public: - char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport.asio.socket"; - } - - std::string message(int value) const { - switch(value) { - case error::security: - return "Security policy error"; - case error::socket: - return "Socket component error"; - case error::invalid_state: - return "Invalid state"; - case error::invalid_tls_context: - return "Invalid or empty TLS context supplied"; - case error::tls_handshake_timeout: - return "TLS handshake timed out"; - case error::pass_through: - return "Pass through from socket policy"; - case error::missing_tls_init_handler: - return "Required tls_init handler not present."; - case error::tls_handshake_failed: - return "TLS handshake failed"; - case error::tls_failed_sni_hostname: - return "Failed to set TLS SNI hostname"; - default: - return "Unknown"; - } - } -}; - -inline lib::error_category const & get_socket_category() { - static socket_category instance; - return instance; -} - -inline lib::error_code make_error_code(error::value e) { - return lib::error_code(static_cast(e), get_socket_category()); -} - -/// Type of asio transport socket policy initialization handlers -typedef lib::function init_handler; - -} // namespace socket -} // namespace asio -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP +/* + * 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_SOCKET_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP + +#include +#include +#include +#include +#include +#include + +#include + +// Interface that sockets/security policies must implement + +/* + * Endpoint Interface + * + * bool is_secure() const; + * @return Whether or not the endpoint creates secure connections + * + * lib::error_code init(socket_con_ptr scon); + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. + * @param scon Pointer to the socket component of the connection + * @return Error code (empty on success) + */ + + +// Connection +// TODO +// set_hostname(std::string hostname) +// pre_init(init_handler); +// post_init(init_handler); + +namespace websocketpp { +namespace transport { +namespace asio { +namespace socket { + +typedef lib::function shutdown_handler; + +/** + * The transport::asio::socket::* classes are a set of security/socket related + * policies and support code for the ASIO transport types. + */ + +/// Errors related to asio transport sockets +namespace error { + enum value { + /// Catch-all error for security policy errors that don't fit in other + /// categories + security = 1, + + /// Catch-all error for socket component errors that don't fit in other + /// categories + socket, + + /// A function was called in a state that it was illegal to do so. + invalid_state, + + /// The application was prompted to provide a TLS context and it was + /// empty or otherwise invalid + invalid_tls_context, + + /// TLS Handshake Timeout + tls_handshake_timeout, + + /// pass_through from underlying library + pass_through, + + /// Required tls_init handler not present + missing_tls_init_handler, + + /// TLS Handshake Failed + tls_handshake_failed, + + /// Failed to set TLS SNI hostname + tls_failed_sni_hostname + }; +} // namespace error + +/// Error category related to asio transport socket policies +class socket_category : public lib::error_category { +public: + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.asio.socket"; + } + + std::string message(int value) const { + switch(value) { + case error::security: + return "Security policy error"; + case error::socket: + return "Socket component error"; + case error::invalid_state: + return "Invalid state"; + case error::invalid_tls_context: + return "Invalid or empty TLS context supplied"; + case error::tls_handshake_timeout: + return "TLS handshake timed out"; + case error::pass_through: + return "Pass through from socket policy"; + case error::missing_tls_init_handler: + return "Required tls_init handler not present."; + case error::tls_handshake_failed: + return "TLS handshake failed"; + case error::tls_failed_sni_hostname: + return "Failed to set TLS SNI hostname"; + default: + return "Unknown"; + } + } +}; + +inline lib::error_category const & get_socket_category() { + static socket_category instance; + return instance; +} + +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_socket_category()); +} + +/// Type of asio transport socket policy initialization handlers +typedef lib::function init_handler; + +} // namespace socket +} // namespace asio +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/none.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/none.hpp index a108885..6c7d352 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/none.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/none.hpp @@ -1,372 +1,372 @@ -/* - * 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_SECURITY_NONE_HPP -#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP - -#include - -#include -#include - -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace asio { -/// A socket policy for the asio transport that implements a plain, unencrypted -/// socket -namespace basic_socket { - -/// The signature of the socket init handler for this socket policy -typedef lib::function - socket_init_handler; - -/// Basic Asio connection socket component -/** - * transport::asio::basic_socket::connection implements a connection socket - * component using Asio ip::tcp::socket. - */ -class connection : public lib::enable_shared_from_this { -public: - /// Type of this connection socket component - typedef connection type; - /// Type of a shared pointer to this connection socket component - typedef lib::shared_ptr ptr; - - /// Type of a pointer to the Asio io_service being used - typedef lib::asio::io_service* io_service_ptr; - /// Type of a pointer to the Asio io_service strand being used - typedef lib::shared_ptr strand_ptr; - /// Type of the ASIO socket being used - typedef lib::asio::ip::tcp::socket socket_type; - /// Type of a shared pointer to the socket being used. - typedef lib::shared_ptr socket_ptr; - - explicit connection() : m_state(UNINITIALIZED) { - //std::cout << "transport::asio::basic_socket::connection constructor" - // << std::endl; - } - - /// Get a shared pointer to this component - ptr get_shared() { - return shared_from_this(); - } - - /// Check whether or not this connection is secure - /** - * @return Whether or not this connection is secure - */ - bool is_secure() const { - return false; - } - - /// Set the socket initialization handler - /** - * The socket initialization handler is called after the socket object is - * created but before it is used. This gives the application a chance to - * set any Asio socket options it needs. - * - * @param h The new socket_init_handler - */ - void set_socket_init_handler(socket_init_handler h) { - m_socket_init_handler = h; - } - - /// Retrieve a pointer to the underlying socket - /** - * This is used internally. It can also be used to set socket options, etc - */ - lib::asio::ip::tcp::socket & get_socket() { - return *m_socket; - } - - /// Retrieve a pointer to the underlying socket - /** - * This is used internally. - */ - lib::asio::ip::tcp::socket & get_next_layer() { - return *m_socket; - } - - /// Retrieve a pointer to the underlying socket - /** - * This is used internally. It can also be used to set socket options, etc - */ - lib::asio::ip::tcp::socket & get_raw_socket() { - return *m_socket; - } - - /// Get the remote endpoint address - /** - * The iostream transport has no information about the ultimate remote - * endpoint. It will return the string "iostream transport". To indicate - * this. - * - * TODO: allow user settable remote endpoint addresses if this seems useful - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint(lib::error_code & ec) const { - std::stringstream s; - - lib::asio::error_code aec; - lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec); - - if (aec) { - ec = error::make_error_code(error::pass_through); - s << "Error getting remote endpoint: " << aec - << " (" << aec.message() << ")"; - return s.str(); - } else { - ec = lib::error_code(); - s << ep; - return s.str(); - } - } -protected: - /// Perform one time initializations - /** - * init_asio is called once immediately after construction to initialize - * Asio components to the io_service - * - * @param service A pointer to the endpoint's io_service - * @param strand A shared pointer to the connection's asio strand - * @param is_server Whether or not the endpoint is a server or not. - */ - lib::error_code init_asio (io_service_ptr service, strand_ptr, bool) - { - if (m_state != UNINITIALIZED) { - return socket::make_error_code(socket::error::invalid_state); - } - - m_socket.reset(new lib::asio::ip::tcp::socket(*service)); - - if (m_socket_init_handler) { - m_socket_init_handler(m_hdl, *m_socket); - } - - m_state = READY; - - return lib::error_code(); - } - - /// Set uri hook - /** - * Called by the transport as a connection is being established to provide - * the uri being connected to to the security/socket layer. - * - * This socket policy doesn't use the uri so it is ignored. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr) {} - - /// Pre-initialize security policy - /** - * Called by the transport after a new connection is created to initialize - * the socket component of the connection. This method is not allowed to - * write any bytes to the wire. This initialization happens before any - * proxies or other intermediate wrappers are negotiated. - * - * @param callback Handler to call back with completion information - */ - void pre_init(init_handler callback) { - if (m_state != READY) { - callback(socket::make_error_code(socket::error::invalid_state)); - return; - } - - m_state = READING; - - callback(lib::error_code()); - } - - /// Post-initialize security policy - /** - * Called by the transport after all intermediate proxies have been - * negotiated. This gives the security policy the chance to talk with the - * real remote endpoint for a bit before the websocket handshake. - * - * @param callback Handler to call back with completion information - */ - void post_init(init_handler callback) { - callback(lib::error_code()); - } - - /// Sets the connection handle - /** - * The connection handle is passed to any handlers to identify the - * connection - * - * @param hdl The new handle - */ - void set_handle(connection_hdl hdl) { - m_hdl = hdl; - } - - /// Cancel all async operations on this socket - /** - * Attempts to cancel all async operations on this socket and reports any - * failures. - * - * NOTE: Windows XP and earlier do not support socket cancellation. - * - * @return The error that occurred, if any. - */ - lib::asio::error_code cancel_socket() { - lib::asio::error_code ec; - m_socket->cancel(ec); - return ec; - } - - void async_shutdown(socket::shutdown_handler h) { - lib::asio::error_code ec; - m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec); - h(ec); - } - - lib::error_code get_ec() const { - return lib::error_code(); - } - -public: - /// Translate any security policy specific information about an error code - /** - * Translate_ec takes an Asio error code and attempts to convert its value - * to an appropriate websocketpp error code. In the case that the Asio and - * Websocketpp error types are the same (such as using boost::asio and - * boost::system_error or using standalone asio and std::system_error the - * code will be passed through natively. - * - * In the case of a mismatch (boost::asio with std::system_error) a - * translated code will be returned. The plain socket policy does not have - * any additional information so all such errors will be reported as the - * generic transport pass_through error. - * - * @since 0.3.0 - * - * @param ec The error code to translate_ec - * @return The translated error code - */ - template - static - lib::error_code translate_ec(ErrorCodeType) { - // We don't know any more information about this error so pass through - return make_error_code(transport::error::pass_through); - } - - static - /// Overload of translate_ec to catch cases where lib::error_code is the - /// same type as lib::asio::error_code - lib::error_code translate_ec(lib::error_code ec) { - // We don't know any more information about this error, but the error is - // the same type as the one we are translating to, so pass through - // untranslated. - return ec; - } -private: - enum state { - UNINITIALIZED = 0, - READY = 1, - READING = 2 - }; - - socket_ptr m_socket; - state m_state; - - connection_hdl m_hdl; - socket_init_handler m_socket_init_handler; -}; - -/// Basic ASIO endpoint socket component -/** - * transport::asio::basic_socket::endpoint implements an endpoint socket - * component that uses Boost ASIO's ip::tcp::socket. - */ -class endpoint { -public: - /// The type of this endpoint socket component - typedef endpoint type; - - /// The type of the corresponding connection socket component - typedef connection socket_con_type; - /// The type of a shared pointer to the corresponding connection socket - /// component. - typedef socket_con_type::ptr socket_con_ptr; - - explicit endpoint() {} - - /// Checks whether the endpoint creates secure connections - /** - * @return Whether or not the endpoint creates secure connections - */ - bool is_secure() const { - return false; - } - - /// Set socket init handler - /** - * The socket init handler is called after a connection's socket is created - * but before it is used. This gives the end application an opportunity to - * set asio socket specific parameters. - * - * @param h The new socket_init_handler - */ - void set_socket_init_handler(socket_init_handler h) { - m_socket_init_handler = h; - } -protected: - /// Initialize a connection - /** - * Called by the transport after a new connection is created to initialize - * the socket component of the connection. - * - * @param scon Pointer to the socket component of the connection - * - * @return Error code (empty on success) - */ - lib::error_code init(socket_con_ptr scon) { - scon->set_socket_init_handler(m_socket_init_handler); - return lib::error_code(); - } -private: - socket_init_handler m_socket_init_handler; -}; - -} // namespace basic_socket -} // namespace asio -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP +/* + * 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_SECURITY_NONE_HPP +#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace asio { +/// A socket policy for the asio transport that implements a plain, unencrypted +/// socket +namespace basic_socket { + +/// The signature of the socket init handler for this socket policy +typedef lib::function + socket_init_handler; + +/// Basic Asio connection socket component +/** + * transport::asio::basic_socket::connection implements a connection socket + * component using Asio ip::tcp::socket. + */ +class connection : public lib::enable_shared_from_this { +public: + /// Type of this connection socket component + typedef connection type; + /// Type of a shared pointer to this connection socket component + typedef lib::shared_ptr ptr; + + /// Type of a pointer to the Asio io_service being used + typedef lib::asio::io_service* io_service_ptr; + /// Type of a pointer to the Asio io_service strand being used + typedef lib::shared_ptr strand_ptr; + /// Type of the ASIO socket being used + typedef lib::asio::ip::tcp::socket socket_type; + /// Type of a shared pointer to the socket being used. + typedef lib::shared_ptr socket_ptr; + + explicit connection() : m_state(UNINITIALIZED) { + //std::cout << "transport::asio::basic_socket::connection constructor" + // << std::endl; + } + + /// Get a shared pointer to this component + ptr get_shared() { + return shared_from_this(); + } + + /// Check whether or not this connection is secure + /** + * @return Whether or not this connection is secure + */ + bool is_secure() const { + return false; + } + + /// Set the socket initialization handler + /** + * The socket initialization handler is called after the socket object is + * created but before it is used. This gives the application a chance to + * set any Asio socket options it needs. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + + /// Retrieve a pointer to the underlying socket + /** + * This is used internally. It can also be used to set socket options, etc + */ + lib::asio::ip::tcp::socket & get_socket() { + return *m_socket; + } + + /// Retrieve a pointer to the underlying socket + /** + * This is used internally. + */ + lib::asio::ip::tcp::socket & get_next_layer() { + return *m_socket; + } + + /// Retrieve a pointer to the underlying socket + /** + * This is used internally. It can also be used to set socket options, etc + */ + lib::asio::ip::tcp::socket & get_raw_socket() { + return *m_socket; + } + + /// Get the remote endpoint address + /** + * The iostream transport has no information about the ultimate remote + * endpoint. It will return the string "iostream transport". To indicate + * this. + * + * TODO: allow user settable remote endpoint addresses if this seems useful + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint(lib::error_code & ec) const { + std::stringstream s; + + lib::asio::error_code aec; + lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec); + + if (aec) { + ec = error::make_error_code(error::pass_through); + s << "Error getting remote endpoint: " << aec + << " (" << aec.message() << ")"; + return s.str(); + } else { + ec = lib::error_code(); + s << ep; + return s.str(); + } + } +protected: + /// Perform one time initializations + /** + * init_asio is called once immediately after construction to initialize + * Asio components to the io_service + * + * @param service A pointer to the endpoint's io_service + * @param strand A shared pointer to the connection's asio strand + * @param is_server Whether or not the endpoint is a server or not. + */ + lib::error_code init_asio (io_service_ptr service, strand_ptr, bool) + { + if (m_state != UNINITIALIZED) { + return socket::make_error_code(socket::error::invalid_state); + } + + m_socket.reset(new lib::asio::ip::tcp::socket(*service)); + + if (m_socket_init_handler) { + m_socket_init_handler(m_hdl, *m_socket); + } + + m_state = READY; + + return lib::error_code(); + } + + /// Set uri hook + /** + * Called by the transport as a connection is being established to provide + * the uri being connected to to the security/socket layer. + * + * This socket policy doesn't use the uri so it is ignored. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + + /// Pre-initialize security policy + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. This method is not allowed to + * write any bytes to the wire. This initialization happens before any + * proxies or other intermediate wrappers are negotiated. + * + * @param callback Handler to call back with completion information + */ + void pre_init(init_handler callback) { + if (m_state != READY) { + callback(socket::make_error_code(socket::error::invalid_state)); + return; + } + + m_state = READING; + + callback(lib::error_code()); + } + + /// Post-initialize security policy + /** + * Called by the transport after all intermediate proxies have been + * negotiated. This gives the security policy the chance to talk with the + * real remote endpoint for a bit before the websocket handshake. + * + * @param callback Handler to call back with completion information + */ + void post_init(init_handler callback) { + callback(lib::error_code()); + } + + /// Sets the connection handle + /** + * The connection handle is passed to any handlers to identify the + * connection + * + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) { + m_hdl = hdl; + } + + /// Cancel all async operations on this socket + /** + * Attempts to cancel all async operations on this socket and reports any + * failures. + * + * NOTE: Windows XP and earlier do not support socket cancellation. + * + * @return The error that occurred, if any. + */ + lib::asio::error_code cancel_socket() { + lib::asio::error_code ec; + m_socket->cancel(ec); + return ec; + } + + void async_shutdown(socket::shutdown_handler h) { + lib::asio::error_code ec; + m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec); + h(ec); + } + + lib::error_code get_ec() const { + return lib::error_code(); + } + +public: + /// Translate any security policy specific information about an error code + /** + * Translate_ec takes an Asio error code and attempts to convert its value + * to an appropriate websocketpp error code. In the case that the Asio and + * Websocketpp error types are the same (such as using boost::asio and + * boost::system_error or using standalone asio and std::system_error the + * code will be passed through natively. + * + * In the case of a mismatch (boost::asio with std::system_error) a + * translated code will be returned. The plain socket policy does not have + * any additional information so all such errors will be reported as the + * generic transport pass_through error. + * + * @since 0.3.0 + * + * @param ec The error code to translate_ec + * @return The translated error code + */ + template + static + lib::error_code translate_ec(ErrorCodeType) { + // We don't know any more information about this error so pass through + return make_error_code(transport::error::pass_through); + } + + static + /// Overload of translate_ec to catch cases where lib::error_code is the + /// same type as lib::asio::error_code + lib::error_code translate_ec(lib::error_code ec) { + // We don't know any more information about this error, but the error is + // the same type as the one we are translating to, so pass through + // untranslated. + return ec; + } +private: + enum state { + UNINITIALIZED = 0, + READY = 1, + READING = 2 + }; + + socket_ptr m_socket; + state m_state; + + connection_hdl m_hdl; + socket_init_handler m_socket_init_handler; +}; + +/// Basic ASIO endpoint socket component +/** + * transport::asio::basic_socket::endpoint implements an endpoint socket + * component that uses Boost ASIO's ip::tcp::socket. + */ +class endpoint { +public: + /// The type of this endpoint socket component + typedef endpoint type; + + /// The type of the corresponding connection socket component + typedef connection socket_con_type; + /// The type of a shared pointer to the corresponding connection socket + /// component. + typedef socket_con_type::ptr socket_con_ptr; + + explicit endpoint() {} + + /// Checks whether the endpoint creates secure connections + /** + * @return Whether or not the endpoint creates secure connections + */ + bool is_secure() const { + return false; + } + + /// Set socket init handler + /** + * The socket init handler is called after a connection's socket is created + * but before it is used. This gives the end application an opportunity to + * set asio socket specific parameters. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } +protected: + /// Initialize a connection + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. + * + * @param scon Pointer to the socket component of the connection + * + * @return Error code (empty on success) + */ + lib::error_code init(socket_con_ptr scon) { + scon->set_socket_init_handler(m_socket_init_handler); + return lib::error_code(); + } +private: + socket_init_handler m_socket_init_handler; +}; + +} // namespace basic_socket +} // namespace asio +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/tls.hpp b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/tls.hpp index 660c55e..04ac379 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/asio/security/tls.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/asio/security/tls.hpp @@ -1,474 +1,474 @@ -/* - * 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_SECURITY_TLS_HPP -#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace asio { -/// A socket policy for the asio transport that implements a TLS encrypted -/// socket by wrapping with an asio::ssl::stream -namespace tls_socket { - -/// The signature of the socket_init_handler for this socket policy -typedef lib::function&)> socket_init_handler; -/// The signature of the tls_init_handler for this socket policy -typedef lib::function(connection_hdl)> - tls_init_handler; - -/// TLS enabled Asio connection socket component -/** - * transport::asio::tls_socket::connection implements a secure connection socket - * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. - */ -class connection : public lib::enable_shared_from_this { -public: - /// Type of this connection socket component - typedef connection type; - /// Type of a shared pointer to this connection socket component - typedef lib::shared_ptr ptr; - - /// Type of the ASIO socket being used - typedef lib::asio::ssl::stream socket_type; - /// Type of a shared pointer to the ASIO socket being used - typedef lib::shared_ptr socket_ptr; - /// Type of a pointer to the ASIO io_service being used - typedef lib::asio::io_service * io_service_ptr; - /// Type of a pointer to the ASIO io_service strand being used - typedef lib::shared_ptr strand_ptr; - /// Type of a shared pointer to the ASIO TLS context being used - typedef lib::shared_ptr context_ptr; - - explicit connection() { - //std::cout << "transport::asio::tls_socket::connection constructor" - // << std::endl; - } - - /// Get a shared pointer to this component - ptr get_shared() { - return shared_from_this(); - } - - /// Check whether or not this connection is secure - /** - * @return Whether or not this connection is secure - */ - bool is_secure() const { - return true; - } - - /// Retrieve a pointer to the underlying socket - /** - * This is used internally. It can also be used to set socket options, etc - */ - socket_type::lowest_layer_type & get_raw_socket() { - return m_socket->lowest_layer(); - } - - /// Retrieve a pointer to the layer below the ssl stream - /** - * This is used internally. - */ - socket_type::next_layer_type & get_next_layer() { - return m_socket->next_layer(); - } - - /// Retrieve a pointer to the wrapped socket - /** - * This is used internally. - */ - socket_type & get_socket() { - return *m_socket; - } - - /// Set the socket initialization handler - /** - * The socket initialization handler is called after the socket object is - * created but before it is used. This gives the application a chance to - * set any ASIO socket options it needs. - * - * @param h The new socket_init_handler - */ - void set_socket_init_handler(socket_init_handler h) { - m_socket_init_handler = h; - } - - /// Set TLS init handler - /** - * The tls init handler is called when needed to request a TLS context for - * the library to use. A TLS init handler must be set and it must return a - * valid TLS context in order for this endpoint to be able to initialize - * TLS connections - * - * @param h The new tls_init_handler - */ - void set_tls_init_handler(tls_init_handler h) { - m_tls_init_handler = h; - } - - /// Get the remote endpoint address - /** - * The iostream transport has no information about the ultimate remote - * endpoint. It will return the string "iostream transport". To indicate - * this. - * - * TODO: allow user settable remote endpoint addresses if this seems useful - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint(lib::error_code & ec) const { - std::stringstream s; - - lib::asio::error_code aec; - lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec); - - if (aec) { - ec = error::make_error_code(error::pass_through); - s << "Error getting remote endpoint: " << aec - << " (" << aec.message() << ")"; - return s.str(); - } else { - ec = lib::error_code(); - s << ep; - return s.str(); - } - } -protected: - /// Perform one time initializations - /** - * init_asio is called once immediately after construction to initialize - * Asio components to the io_service - * - * @param service A pointer to the endpoint's io_service - * @param strand A pointer to the connection's strand - * @param is_server Whether or not the endpoint is a server or not. - */ - lib::error_code init_asio (io_service_ptr service, strand_ptr strand, - bool is_server) - { - if (!m_tls_init_handler) { - return socket::make_error_code(socket::error::missing_tls_init_handler); - } - m_context = m_tls_init_handler(m_hdl); - - if (!m_context) { - return socket::make_error_code(socket::error::invalid_tls_context); - } - m_socket.reset(new socket_type(*service, *m_context)); - - if (m_socket_init_handler) { - m_socket_init_handler(m_hdl, get_socket()); - } - - m_io_service = service; - m_strand = strand; - m_is_server = is_server; - - return lib::error_code(); - } - - /// Set hostname hook - /** - * Called by the transport as a connection is being established to provide - * the hostname being connected to to the security/socket layer. - * - * This socket policy uses the hostname to set the appropriate TLS SNI - * header. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr u) { - m_uri = u; - } - - /// Pre-initialize security policy - /** - * Called by the transport after a new connection is created to initialize - * the socket component of the connection. This method is not allowed to - * write any bytes to the wire. This initialization happens before any - * proxies or other intermediate wrappers are negotiated. - * - * @param callback Handler to call back with completion information - */ - void pre_init(init_handler callback) { - // TODO: is this the best way to check whether this function is - // available in the version of OpenSSL being used? - // TODO: consider case where host is an IP address -#if OPENSSL_VERSION_NUMBER >= 0x90812f - if (!m_is_server) { - // For clients on systems with a suitable OpenSSL version, set the - // TLS SNI hostname header so connecting to TLS servers using SNI - // will work. - long res = SSL_set_tlsext_host_name( - get_socket().native_handle(), m_uri->get_host().c_str()); - if (!(1 == res)) { - callback(socket::make_error_code(socket::error::tls_failed_sni_hostname)); - } - } -#endif - - callback(lib::error_code()); - } - - /// Post-initialize security policy - /** - * Called by the transport after all intermediate proxies have been - * negotiated. This gives the security policy the chance to talk with the - * real remote endpoint for a bit before the websocket handshake. - * - * @param callback Handler to call back with completion information - */ - void post_init(init_handler callback) { - m_ec = socket::make_error_code(socket::error::tls_handshake_timeout); - - // TLS handshake - if (m_strand) { - m_socket->async_handshake( - get_handshake_type(), - m_strand->wrap(lib::bind( - &type::handle_init, get_shared(), - callback, - lib::placeholders::_1 - )) - ); - } else { - m_socket->async_handshake( - get_handshake_type(), - lib::bind( - &type::handle_init, get_shared(), - callback, - lib::placeholders::_1 - ) - ); - } - } - - /// Sets the connection handle - /** - * The connection handle is passed to any handlers to identify the - * connection - * - * @param hdl The new handle - */ - void set_handle(connection_hdl hdl) { - m_hdl = hdl; - } - - void handle_init(init_handler callback,lib::asio::error_code const & ec) { - if (ec) { - m_ec = socket::make_error_code(socket::error::tls_handshake_failed); - } else { - m_ec = lib::error_code(); - } - - callback(m_ec); - } - - lib::error_code get_ec() const { - return m_ec; - } - - /// Cancel all async operations on this socket - /** - * Attempts to cancel all async operations on this socket and reports any - * failures. - * - * NOTE: Windows XP and earlier do not support socket cancellation. - * - * @return The error that occurred, if any. - */ - lib::asio::error_code cancel_socket() { - lib::asio::error_code ec; - get_raw_socket().cancel(ec); - return ec; - } - - void async_shutdown(socket::shutdown_handler callback) { - if (m_strand) { - m_socket->async_shutdown(m_strand->wrap(callback)); - } else { - m_socket->async_shutdown(callback); - } - } - -public: - /// Translate any security policy specific information about an error code - /** - * Translate_ec takes an Asio error code and attempts to convert its value - * to an appropriate websocketpp error code. In the case that the Asio and - * Websocketpp error types are the same (such as using boost::asio and - * boost::system_error or using standalone asio and std::system_error the - * code will be passed through natively. - * - * In the case of a mismatch (boost::asio with std::system_error) a - * translated code will be returned. Any error that is determined to be - * related to TLS but does not have a more specific websocketpp error code - * is returned under the catch all error `tls_error`. Non-TLS related errors - * are returned as the transport generic error `pass_through` - * - * @since 0.3.0 - * - * @param ec The error code to translate_ec - * @return The translated error code - */ - template - static - lib::error_code translate_ec(ErrorCodeType ec) { - if (ec.category() == lib::asio::error::get_ssl_category()) { - // We know it is a TLS related error, but otherwise don't know more. - // Pass through as TLS generic. - return make_error_code(transport::error::tls_error); - } else { - // We don't know any more information about this error so pass - // through - return make_error_code(transport::error::pass_through); - } - } - - static - /// Overload of translate_ec to catch cases where lib::error_code is the - /// same type as lib::asio::error_code - lib::error_code translate_ec(lib::error_code ec) { - return ec; - } -private: - socket_type::handshake_type get_handshake_type() { - if (m_is_server) { - return lib::asio::ssl::stream_base::server; - } else { - return lib::asio::ssl::stream_base::client; - } - } - - io_service_ptr m_io_service; - strand_ptr m_strand; - context_ptr m_context; - socket_ptr m_socket; - uri_ptr m_uri; - bool m_is_server; - - lib::error_code m_ec; - - connection_hdl m_hdl; - socket_init_handler m_socket_init_handler; - tls_init_handler m_tls_init_handler; -}; - -/// TLS enabled Asio endpoint socket component -/** - * transport::asio::tls_socket::endpoint implements a secure endpoint socket - * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. - */ -class endpoint { -public: - /// The type of this endpoint socket component - typedef endpoint type; - - /// The type of the corresponding connection socket component - typedef connection socket_con_type; - /// The type of a shared pointer to the corresponding connection socket - /// component. - typedef socket_con_type::ptr socket_con_ptr; - - explicit endpoint() {} - - /// Checks whether the endpoint creates secure connections - /** - * @return Whether or not the endpoint creates secure connections - */ - bool is_secure() const { - return true; - } - - /// Set socket init handler - /** - * The socket init handler is called after a connection's socket is created - * but before it is used. This gives the end application an opportunity to - * set asio socket specific parameters. - * - * @param h The new socket_init_handler - */ - void set_socket_init_handler(socket_init_handler h) { - m_socket_init_handler = h; - } - - /// Set TLS init handler - /** - * The tls init handler is called when needed to request a TLS context for - * the library to use. A TLS init handler must be set and it must return a - * valid TLS context in order for this endpoint to be able to initialize - * TLS connections - * - * @param h The new tls_init_handler - */ - void set_tls_init_handler(tls_init_handler h) { - m_tls_init_handler = h; - } -protected: - /// Initialize a connection - /** - * Called by the transport after a new connection is created to initialize - * the socket component of the connection. - * - * @param scon Pointer to the socket component of the connection - * - * @return Error code (empty on success) - */ - lib::error_code init(socket_con_ptr scon) { - scon->set_socket_init_handler(m_socket_init_handler); - scon->set_tls_init_handler(m_tls_init_handler); - return lib::error_code(); - } - -private: - socket_init_handler m_socket_init_handler; - tls_init_handler m_tls_init_handler; -}; - -} // namespace tls_socket -} // namespace asio -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP +/* + * 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_SECURITY_TLS_HPP +#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace asio { +/// A socket policy for the asio transport that implements a TLS encrypted +/// socket by wrapping with an asio::ssl::stream +namespace tls_socket { + +/// The signature of the socket_init_handler for this socket policy +typedef lib::function&)> socket_init_handler; +/// The signature of the tls_init_handler for this socket policy +typedef lib::function(connection_hdl)> + tls_init_handler; + +/// TLS enabled Asio connection socket component +/** + * transport::asio::tls_socket::connection implements a secure connection socket + * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. + */ +class connection : public lib::enable_shared_from_this { +public: + /// Type of this connection socket component + typedef connection type; + /// Type of a shared pointer to this connection socket component + typedef lib::shared_ptr ptr; + + /// Type of the ASIO socket being used + typedef lib::asio::ssl::stream socket_type; + /// Type of a shared pointer to the ASIO socket being used + typedef lib::shared_ptr socket_ptr; + /// Type of a pointer to the ASIO io_service being used + typedef lib::asio::io_service * io_service_ptr; + /// Type of a pointer to the ASIO io_service strand being used + typedef lib::shared_ptr strand_ptr; + /// Type of a shared pointer to the ASIO TLS context being used + typedef lib::shared_ptr context_ptr; + + explicit connection() { + //std::cout << "transport::asio::tls_socket::connection constructor" + // << std::endl; + } + + /// Get a shared pointer to this component + ptr get_shared() { + return shared_from_this(); + } + + /// Check whether or not this connection is secure + /** + * @return Whether or not this connection is secure + */ + bool is_secure() const { + return true; + } + + /// Retrieve a pointer to the underlying socket + /** + * This is used internally. It can also be used to set socket options, etc + */ + socket_type::lowest_layer_type & get_raw_socket() { + return m_socket->lowest_layer(); + } + + /// Retrieve a pointer to the layer below the ssl stream + /** + * This is used internally. + */ + socket_type::next_layer_type & get_next_layer() { + return m_socket->next_layer(); + } + + /// Retrieve a pointer to the wrapped socket + /** + * This is used internally. + */ + socket_type & get_socket() { + return *m_socket; + } + + /// Set the socket initialization handler + /** + * The socket initialization handler is called after the socket object is + * created but before it is used. This gives the application a chance to + * set any ASIO socket options it needs. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + + /// Set TLS init handler + /** + * The tls init handler is called when needed to request a TLS context for + * the library to use. A TLS init handler must be set and it must return a + * valid TLS context in order for this endpoint to be able to initialize + * TLS connections + * + * @param h The new tls_init_handler + */ + void set_tls_init_handler(tls_init_handler h) { + m_tls_init_handler = h; + } + + /// Get the remote endpoint address + /** + * The iostream transport has no information about the ultimate remote + * endpoint. It will return the string "iostream transport". To indicate + * this. + * + * TODO: allow user settable remote endpoint addresses if this seems useful + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint(lib::error_code & ec) const { + std::stringstream s; + + lib::asio::error_code aec; + lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec); + + if (aec) { + ec = error::make_error_code(error::pass_through); + s << "Error getting remote endpoint: " << aec + << " (" << aec.message() << ")"; + return s.str(); + } else { + ec = lib::error_code(); + s << ep; + return s.str(); + } + } +protected: + /// Perform one time initializations + /** + * init_asio is called once immediately after construction to initialize + * Asio components to the io_service + * + * @param service A pointer to the endpoint's io_service + * @param strand A pointer to the connection's strand + * @param is_server Whether or not the endpoint is a server or not. + */ + lib::error_code init_asio (io_service_ptr service, strand_ptr strand, + bool is_server) + { + if (!m_tls_init_handler) { + return socket::make_error_code(socket::error::missing_tls_init_handler); + } + m_context = m_tls_init_handler(m_hdl); + + if (!m_context) { + return socket::make_error_code(socket::error::invalid_tls_context); + } + m_socket.reset(new socket_type(*service, *m_context)); + + if (m_socket_init_handler) { + m_socket_init_handler(m_hdl, get_socket()); + } + + m_io_service = service; + m_strand = strand; + m_is_server = is_server; + + return lib::error_code(); + } + + /// Set hostname hook + /** + * Called by the transport as a connection is being established to provide + * the hostname being connected to to the security/socket layer. + * + * This socket policy uses the hostname to set the appropriate TLS SNI + * header. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr u) { + m_uri = u; + } + + /// Pre-initialize security policy + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. This method is not allowed to + * write any bytes to the wire. This initialization happens before any + * proxies or other intermediate wrappers are negotiated. + * + * @param callback Handler to call back with completion information + */ + void pre_init(init_handler callback) { + // TODO: is this the best way to check whether this function is + // available in the version of OpenSSL being used? + // TODO: consider case where host is an IP address +#if OPENSSL_VERSION_NUMBER >= 0x90812f + if (!m_is_server) { + // For clients on systems with a suitable OpenSSL version, set the + // TLS SNI hostname header so connecting to TLS servers using SNI + // will work. + long res = SSL_set_tlsext_host_name( + get_socket().native_handle(), m_uri->get_host().c_str()); + if (!(1 == res)) { + callback(socket::make_error_code(socket::error::tls_failed_sni_hostname)); + } + } +#endif + + callback(lib::error_code()); + } + + /// Post-initialize security policy + /** + * Called by the transport after all intermediate proxies have been + * negotiated. This gives the security policy the chance to talk with the + * real remote endpoint for a bit before the websocket handshake. + * + * @param callback Handler to call back with completion information + */ + void post_init(init_handler callback) { + m_ec = socket::make_error_code(socket::error::tls_handshake_timeout); + + // TLS handshake + if (m_strand) { + m_socket->async_handshake( + get_handshake_type(), + m_strand->wrap(lib::bind( + &type::handle_init, get_shared(), + callback, + lib::placeholders::_1 + )) + ); + } else { + m_socket->async_handshake( + get_handshake_type(), + lib::bind( + &type::handle_init, get_shared(), + callback, + lib::placeholders::_1 + ) + ); + } + } + + /// Sets the connection handle + /** + * The connection handle is passed to any handlers to identify the + * connection + * + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) { + m_hdl = hdl; + } + + void handle_init(init_handler callback,lib::asio::error_code const & ec) { + if (ec) { + m_ec = socket::make_error_code(socket::error::tls_handshake_failed); + } else { + m_ec = lib::error_code(); + } + + callback(m_ec); + } + + lib::error_code get_ec() const { + return m_ec; + } + + /// Cancel all async operations on this socket + /** + * Attempts to cancel all async operations on this socket and reports any + * failures. + * + * NOTE: Windows XP and earlier do not support socket cancellation. + * + * @return The error that occurred, if any. + */ + lib::asio::error_code cancel_socket() { + lib::asio::error_code ec; + get_raw_socket().cancel(ec); + return ec; + } + + void async_shutdown(socket::shutdown_handler callback) { + if (m_strand) { + m_socket->async_shutdown(m_strand->wrap(callback)); + } else { + m_socket->async_shutdown(callback); + } + } + +public: + /// Translate any security policy specific information about an error code + /** + * Translate_ec takes an Asio error code and attempts to convert its value + * to an appropriate websocketpp error code. In the case that the Asio and + * Websocketpp error types are the same (such as using boost::asio and + * boost::system_error or using standalone asio and std::system_error the + * code will be passed through natively. + * + * In the case of a mismatch (boost::asio with std::system_error) a + * translated code will be returned. Any error that is determined to be + * related to TLS but does not have a more specific websocketpp error code + * is returned under the catch all error `tls_error`. Non-TLS related errors + * are returned as the transport generic error `pass_through` + * + * @since 0.3.0 + * + * @param ec The error code to translate_ec + * @return The translated error code + */ + template + static + lib::error_code translate_ec(ErrorCodeType ec) { + if (ec.category() == lib::asio::error::get_ssl_category()) { + // We know it is a TLS related error, but otherwise don't know more. + // Pass through as TLS generic. + return make_error_code(transport::error::tls_error); + } else { + // We don't know any more information about this error so pass + // through + return make_error_code(transport::error::pass_through); + } + } + + static + /// Overload of translate_ec to catch cases where lib::error_code is the + /// same type as lib::asio::error_code + lib::error_code translate_ec(lib::error_code ec) { + return ec; + } +private: + socket_type::handshake_type get_handshake_type() { + if (m_is_server) { + return lib::asio::ssl::stream_base::server; + } else { + return lib::asio::ssl::stream_base::client; + } + } + + io_service_ptr m_io_service; + strand_ptr m_strand; + context_ptr m_context; + socket_ptr m_socket; + uri_ptr m_uri; + bool m_is_server; + + lib::error_code m_ec; + + connection_hdl m_hdl; + socket_init_handler m_socket_init_handler; + tls_init_handler m_tls_init_handler; +}; + +/// TLS enabled Asio endpoint socket component +/** + * transport::asio::tls_socket::endpoint implements a secure endpoint socket + * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. + */ +class endpoint { +public: + /// The type of this endpoint socket component + typedef endpoint type; + + /// The type of the corresponding connection socket component + typedef connection socket_con_type; + /// The type of a shared pointer to the corresponding connection socket + /// component. + typedef socket_con_type::ptr socket_con_ptr; + + explicit endpoint() {} + + /// Checks whether the endpoint creates secure connections + /** + * @return Whether or not the endpoint creates secure connections + */ + bool is_secure() const { + return true; + } + + /// Set socket init handler + /** + * The socket init handler is called after a connection's socket is created + * but before it is used. This gives the end application an opportunity to + * set asio socket specific parameters. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + + /// Set TLS init handler + /** + * The tls init handler is called when needed to request a TLS context for + * the library to use. A TLS init handler must be set and it must return a + * valid TLS context in order for this endpoint to be able to initialize + * TLS connections + * + * @param h The new tls_init_handler + */ + void set_tls_init_handler(tls_init_handler h) { + m_tls_init_handler = h; + } +protected: + /// Initialize a connection + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. + * + * @param scon Pointer to the socket component of the connection + * + * @return Error code (empty on success) + */ + lib::error_code init(socket_con_ptr scon) { + scon->set_socket_init_handler(m_socket_init_handler); + scon->set_tls_init_handler(m_tls_init_handler); + return lib::error_code(); + } + +private: + socket_init_handler m_socket_init_handler; + tls_init_handler m_tls_init_handler; +}; + +} // namespace tls_socket +} // namespace asio +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/base/connection.hpp b/thirdparty/websocketpp/include/websocketpp/transport/base/connection.hpp index ce9a4f9..f76d409 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/base/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/base/connection.hpp @@ -1,238 +1,238 @@ -/* - * 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_TRANSPORT_BASE_CON_HPP -#define WEBSOCKETPP_TRANSPORT_BASE_CON_HPP - -#include -#include -#include -#include - -#include - -namespace websocketpp { -/// Transport policies provide network connectivity and timers -/** - * ### Connection Interface - * - * Transport connection components needs to provide: - * - * **init**\n - * `void init(init_handler handler)`\n - * Called once shortly after construction to give the policy the chance to - * perform one time initialization. When complete, the policy must call the - * supplied `init_handler` to continue setup. The handler takes one argument - * with the error code if any. If an error is returned here setup will fail and - * the connection will be aborted or terminated. - * - * WebSocket++ will call init only once. The transport must call `handler` - * exactly once. - * - * **async_read_at_least**\n - * `void async_read_at_least(size_t num_bytes, char *buf, size_t len, - * read_handler handler)`\n - * start an async read for at least num_bytes and at most len - * bytes into buf. Call handler when done with number of bytes read. - * - * WebSocket++ promises to have only one async_read_at_least in flight at a - * time. The transport must promise to only call read_handler once per async - * read. - * - * **async_write**\n - * `void async_write(const char* buf, size_t len, write_handler handler)`\n - * `void async_write(std::vector & bufs, write_handler handler)`\n - * Start a write of all of the data in buf or bufs. In second case data is - * written sequentially and in place without copying anything to a temporary - * location. - * - * Websocket++ promises to have only one async_write in flight at a time. - * The transport must promise to only call the write_handler once per async - * write - * - * **set_handle**\n - * `void set_handle(connection_hdl hdl)`\n - * Called by WebSocket++ to let this policy know the hdl to the connection. It - * may be stored for later use or ignored/discarded. This handle should be used - * if the policy adds any connection handlers. Connection handlers must be - * called with the handle as the first argument so that the handler code knows - * which connection generated the callback. - * - * **set_timer**\n - * `timer_ptr set_timer(long duration, timer_handler handler)`\n - * WebSocket++ uses the timers provided by the transport policy as the - * implementation of timers is often highly coupled with the implementation of - * the networking event loops. - * - * Transport timer support is an optional feature. A transport method may elect - * to implement a dummy timer object and have this method return an empty - * pointer. If so, all timer related features of WebSocket++ core will be - * disabled. This includes many security features designed to prevent denial of - * service attacks. Use timer-free transport policies with caution. - * - * **get_remote_endpoint**\n - * `std::string get_remote_endpoint()`\n - * retrieve address of remote endpoint - * - * **is_secure**\n - * `void is_secure()`\n - * whether or not the connection to the remote endpoint is secure - * - * **dispatch**\n - * `lib::error_code dispatch(dispatch_handler handler)`: invoke handler within - * the transport's event system if it uses one. Otherwise, this method should - * simply call `handler` immediately. - * - * **async_shutdown**\n - * `void async_shutdown(shutdown_handler handler)`\n - * Perform any cleanup necessary (if any). Call `handler` when complete. - */ -namespace transport { - -/// The type and signature of the callback passed to the init hook -typedef lib::function init_handler; - -/// The type and signature of the callback passed to the read method -typedef lib::function read_handler; - -/// The type and signature of the callback passed to the write method -typedef lib::function write_handler; - -/// The type and signature of the callback passed to the read method -typedef lib::function timer_handler; - -/// The type and signature of the callback passed to the shutdown method -typedef lib::function shutdown_handler; - -/// The type and signature of the callback passed to the interrupt method -typedef lib::function interrupt_handler; - -/// The type and signature of the callback passed to the dispatch method -typedef lib::function dispatch_handler; - -/// A simple utility buffer class -struct buffer { - buffer(char const * b, size_t l) : buf(b),len(l) {} - - char const * buf; - size_t len; -}; - -/// Generic transport related errors -namespace error { -enum value { - /// Catch-all error for transport policy errors that don't fit in other - /// categories - general = 1, - - /// underlying transport pass through - pass_through, - - /// async_read_at_least call requested more bytes than buffer can store - invalid_num_bytes, - - /// async_read called while another async_read was in progress - double_read, - - /// Operation aborted - operation_aborted, - - /// Operation not supported - operation_not_supported, - - /// End of file - eof, - - /// TLS short read - tls_short_read, - - /// Timer expired - timeout, - - /// read or write after shutdown - action_after_shutdown, - - /// Other TLS error - tls_error -}; - -class category : public lib::error_category { - public: - category() {} - - char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport"; - } - - std::string message(int value) const { - switch(value) { - case general: - return "Generic transport policy error"; - case pass_through: - return "Underlying Transport Error"; - case invalid_num_bytes: - return "async_read_at_least call requested more bytes than buffer can store"; - case operation_aborted: - return "The operation was aborted"; - case operation_not_supported: - return "The operation is not supported by this transport"; - case eof: - return "End of File"; - case tls_short_read: - return "TLS Short Read"; - case timeout: - return "Timer Expired"; - case action_after_shutdown: - return "A transport action was requested after shutdown"; - case tls_error: - return "Generic TLS related error"; - default: - return "Unknown"; - } - } -}; - -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(e), get_category()); -} - -} // namespace error -} // namespace transport -} // namespace websocketpp -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif // WEBSOCKETPP_TRANSPORT_BASE_CON_HPP +/* + * 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_TRANSPORT_BASE_CON_HPP +#define WEBSOCKETPP_TRANSPORT_BASE_CON_HPP + +#include +#include +#include +#include + +#include + +namespace websocketpp { +/// Transport policies provide network connectivity and timers +/** + * ### Connection Interface + * + * Transport connection components needs to provide: + * + * **init**\n + * `void init(init_handler handler)`\n + * Called once shortly after construction to give the policy the chance to + * perform one time initialization. When complete, the policy must call the + * supplied `init_handler` to continue setup. The handler takes one argument + * with the error code if any. If an error is returned here setup will fail and + * the connection will be aborted or terminated. + * + * WebSocket++ will call init only once. The transport must call `handler` + * exactly once. + * + * **async_read_at_least**\n + * `void async_read_at_least(size_t num_bytes, char *buf, size_t len, + * read_handler handler)`\n + * start an async read for at least num_bytes and at most len + * bytes into buf. Call handler when done with number of bytes read. + * + * WebSocket++ promises to have only one async_read_at_least in flight at a + * time. The transport must promise to only call read_handler once per async + * read. + * + * **async_write**\n + * `void async_write(const char* buf, size_t len, write_handler handler)`\n + * `void async_write(std::vector & bufs, write_handler handler)`\n + * Start a write of all of the data in buf or bufs. In second case data is + * written sequentially and in place without copying anything to a temporary + * location. + * + * Websocket++ promises to have only one async_write in flight at a time. + * The transport must promise to only call the write_handler once per async + * write + * + * **set_handle**\n + * `void set_handle(connection_hdl hdl)`\n + * Called by WebSocket++ to let this policy know the hdl to the connection. It + * may be stored for later use or ignored/discarded. This handle should be used + * if the policy adds any connection handlers. Connection handlers must be + * called with the handle as the first argument so that the handler code knows + * which connection generated the callback. + * + * **set_timer**\n + * `timer_ptr set_timer(long duration, timer_handler handler)`\n + * WebSocket++ uses the timers provided by the transport policy as the + * implementation of timers is often highly coupled with the implementation of + * the networking event loops. + * + * Transport timer support is an optional feature. A transport method may elect + * to implement a dummy timer object and have this method return an empty + * pointer. If so, all timer related features of WebSocket++ core will be + * disabled. This includes many security features designed to prevent denial of + * service attacks. Use timer-free transport policies with caution. + * + * **get_remote_endpoint**\n + * `std::string get_remote_endpoint()`\n + * retrieve address of remote endpoint + * + * **is_secure**\n + * `void is_secure()`\n + * whether or not the connection to the remote endpoint is secure + * + * **dispatch**\n + * `lib::error_code dispatch(dispatch_handler handler)`: invoke handler within + * the transport's event system if it uses one. Otherwise, this method should + * simply call `handler` immediately. + * + * **async_shutdown**\n + * `void async_shutdown(shutdown_handler handler)`\n + * Perform any cleanup necessary (if any). Call `handler` when complete. + */ +namespace transport { + +/// The type and signature of the callback passed to the init hook +typedef lib::function init_handler; + +/// The type and signature of the callback passed to the read method +typedef lib::function read_handler; + +/// The type and signature of the callback passed to the write method +typedef lib::function write_handler; + +/// The type and signature of the callback passed to the read method +typedef lib::function timer_handler; + +/// The type and signature of the callback passed to the shutdown method +typedef lib::function shutdown_handler; + +/// The type and signature of the callback passed to the interrupt method +typedef lib::function interrupt_handler; + +/// The type and signature of the callback passed to the dispatch method +typedef lib::function dispatch_handler; + +/// A simple utility buffer class +struct buffer { + buffer(char const * b, size_t l) : buf(b),len(l) {} + + char const * buf; + size_t len; +}; + +/// Generic transport related errors +namespace error { +enum value { + /// Catch-all error for transport policy errors that don't fit in other + /// categories + general = 1, + + /// underlying transport pass through + pass_through, + + /// async_read_at_least call requested more bytes than buffer can store + invalid_num_bytes, + + /// async_read called while another async_read was in progress + double_read, + + /// Operation aborted + operation_aborted, + + /// Operation not supported + operation_not_supported, + + /// End of file + eof, + + /// TLS short read + tls_short_read, + + /// Timer expired + timeout, + + /// read or write after shutdown + action_after_shutdown, + + /// Other TLS error + tls_error +}; + +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic transport policy error"; + case pass_through: + return "Underlying Transport Error"; + case invalid_num_bytes: + return "async_read_at_least call requested more bytes than buffer can store"; + case operation_aborted: + return "The operation was aborted"; + case operation_not_supported: + return "The operation is not supported by this transport"; + case eof: + return "End of File"; + case tls_short_read: + return "TLS Short Read"; + case timeout: + return "Timer Expired"; + case action_after_shutdown: + return "A transport action was requested after shutdown"; + case tls_error: + return "Generic TLS related error"; + default: + return "Unknown"; + } + } +}; + +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(e), get_category()); +} + +} // namespace error +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_BASE_CON_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/base/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/transport/base/endpoint.hpp index 408b6c8..4ed3e70 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/base/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/base/endpoint.hpp @@ -1,77 +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_TRANSPORT_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_BASE_HPP - -#include -#include - -namespace websocketpp { -/// Transport policies provide network connectivity and timers -/** - * ### Endpoint Interface - * - * Transport endpoint components needs to provide: - * - * **init**\n - * `lib::error_code init(transport_con_ptr tcon)`\n - * init is called by an endpoint once for each newly created connection. - * It's purpose is to give the transport policy the chance to perform any - * transport specific initialization that couldn't be done via the default - * constructor. - * - * **is_secure**\n - * `bool is_secure() const`\n - * Test whether the transport component of this endpoint is capable of secure - * connections. - * - * **async_connect**\n - * `void async_connect(transport_con_ptr tcon, uri_ptr location, - * connect_handler handler)`\n - * Initiate a connection to `location` using the given connection `tcon`. `tcon` - * is a pointer to the transport connection component of the connection. When - * complete, `handler` should be called with the the connection's - * `connection_hdl` and any error that occurred. - * - * **init_logging** - * `void init_logging(const lib::shared_ptr& a, const lib::shared_ptr& e)`\n - * Called once after construction to provide pointers to the endpoint's access - * and error loggers. These may be stored and used to log messages or ignored. - */ -namespace transport { - -/// The type and signature of the callback passed to the accept method -typedef lib::function accept_handler; - -/// The type and signature of the callback passed to the connect method -typedef lib::function connect_handler; - -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_BASE_HPP +/* + * 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_TRANSPORT_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_BASE_HPP + +#include +#include + +namespace websocketpp { +/// Transport policies provide network connectivity and timers +/** + * ### Endpoint Interface + * + * Transport endpoint components needs to provide: + * + * **init**\n + * `lib::error_code init(transport_con_ptr tcon)`\n + * init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * **is_secure**\n + * `bool is_secure() const`\n + * Test whether the transport component of this endpoint is capable of secure + * connections. + * + * **async_connect**\n + * `void async_connect(transport_con_ptr tcon, uri_ptr location, + * connect_handler handler)`\n + * Initiate a connection to `location` using the given connection `tcon`. `tcon` + * is a pointer to the transport connection component of the connection. When + * complete, `handler` should be called with the the connection's + * `connection_hdl` and any error that occurred. + * + * **init_logging** + * `void init_logging(const lib::shared_ptr& a, const lib::shared_ptr& e)`\n + * Called once after construction to provide pointers to the endpoint's access + * and error loggers. These may be stored and used to log messages or ignored. + */ +namespace transport { + +/// The type and signature of the callback passed to the accept method +typedef lib::function accept_handler; + +/// The type and signature of the callback passed to the connect method +typedef lib::function connect_handler; + +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/debug/base.hpp b/thirdparty/websocketpp/include/websocketpp/transport/debug/base.hpp index 18494da..2e477b5 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/debug/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/debug/base.hpp @@ -1,104 +1,104 @@ -/* - * 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_TRANSPORT_DEBUG_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP - -#include -#include - -#include - -namespace websocketpp { -namespace transport { -/// Debug transport policy that is used for various mocking and stubbing duties -/// in unit tests. -namespace debug { - -/// debug transport errors -namespace error { -enum value { - /// Catch-all error for transport policy errors that don't fit in other - /// categories - general = 1, - - /// not implemented - not_implemented, - - invalid_num_bytes, - - double_read -}; - -/// debug transport error category -class category : public lib::error_category { - public: - category() {} - - char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport.debug"; - } - - std::string message(int value) const { - switch(value) { - case general: - return "Generic stub transport policy error"; - case not_implemented: - return "feature not implemented"; - case invalid_num_bytes: - return "Invalid number of bytes"; - case double_read: - return "Read while another read was outstanding"; - default: - return "Unknown"; - } - } -}; - -/// Get a reference to a static copy of the debug transport error category -inline lib::error_category const & get_category() { - static category instance; - return instance; -} - -/// Get an error code with the given value and the debug transport category -inline lib::error_code make_error_code(error::value e) { - return lib::error_code(static_cast(e), get_category()); -} - -} // namespace error -} // namespace debug -} // namespace transport -} // namespace websocketpp -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif // WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP +/* + * 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_TRANSPORT_DEBUG_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP + +#include +#include + +#include + +namespace websocketpp { +namespace transport { +/// Debug transport policy that is used for various mocking and stubbing duties +/// in unit tests. +namespace debug { + +/// debug transport errors +namespace error { +enum value { + /// Catch-all error for transport policy errors that don't fit in other + /// categories + general = 1, + + /// not implemented + not_implemented, + + invalid_num_bytes, + + double_read +}; + +/// debug transport error category +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.debug"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic stub transport policy error"; + case not_implemented: + return "feature not implemented"; + case invalid_num_bytes: + return "Invalid number of bytes"; + case double_read: + return "Read while another read was outstanding"; + default: + return "Unknown"; + } + } +}; + +/// Get a reference to a static copy of the debug transport error category +inline lib::error_category const & get_category() { + static category instance; + return instance; +} + +/// Get an error code with the given value and the debug transport category +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_category()); +} + +} // namespace error +} // namespace debug +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/debug/connection.hpp b/thirdparty/websocketpp/include/websocketpp/transport/debug/connection.hpp index 0cf75b1..ce13969 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/debug/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/debug/connection.hpp @@ -1,412 +1,412 @@ -/* - * 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_TRANSPORT_DEBUG_CON_HPP -#define WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP - -#include - -#include - -#include -#include - -#include -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace debug { - -/// Empty timer class to stub out for timer functionality that stub -/// transport doesn't support -struct timer { - void cancel() {} -}; - -template -class connection : public lib::enable_shared_from_this< connection > { -public: - /// Type of this connection transport component - typedef connection type; - /// Type of a shared pointer to this connection transport component - typedef lib::shared_ptr ptr; - - /// transport concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this transport's access logging policy - typedef typename config::alog_type alog_type; - /// Type of this transport's error logging policy - typedef typename config::elog_type elog_type; - - // Concurrency policy types - typedef typename concurrency_type::scoped_lock_type scoped_lock_type; - typedef typename concurrency_type::mutex_type mutex_type; - - typedef lib::shared_ptr timer_ptr; - - explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) - : m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog) - { - m_alog->write(log::alevel::devel,"debug con transport constructor"); - } - - /// Get a shared pointer to this component - ptr get_shared() { - return type::shared_from_this(); - } - - /// Set whether or not this connection is secure - /** - * Todo: docs - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not this connection is secure. - */ - void set_secure(bool) {} - - /// Tests whether or not the underlying transport is secure - /** - * TODO: docs - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return false; - } - - /// Set uri hook - /** - * Called by the endpoint as a connection is being established to provide - * the uri being connected to to the transport layer. - * - * Implementation is optional and can be ignored if the transport has no - * need for this information. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr) {} - - /// Set human readable remote endpoint address - /** - * Sets the remote endpoint address returned by `get_remote_endpoint`. This - * value should be a human readable string that describes the remote - * endpoint. Typically an IP address or hostname, perhaps with a port. But - * may be something else depending on the nature of the underlying - * transport. - * - * If none is set a default is returned. - * - * @since 0.3.0-alpha4 - * - * @param value The remote endpoint address to set. - */ - void set_remote_endpoint(std::string) {} - - /// Get human readable remote endpoint address - /** - * TODO: docs - * - * This value is used in access and error logs and is available to the end - * application for including in user facing interfaces and messages. - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint() const { - return "unknown (debug transport)"; - } - - /// Get the connection handle - /** - * @return The handle for this connection. - */ - connection_hdl get_handle() const { - return connection_hdl(); - } - - /// Call back a function after a period of time. - /** - * Timers are not implemented in this transport. The timer pointer will - * always be empty. The handler will never be called. - * - * @param duration Length of time to wait in milliseconds - * @param callback The function to call back when the timer has expired - * @return A handle that can be used to cancel the timer if it is no longer - * needed. - */ - timer_ptr set_timer(long, timer_handler handler) { - m_alog->write(log::alevel::devel,"debug connection set timer"); - m_timer_handler = handler; - return timer_ptr(); - } - - /// Manual input supply (read all) - /** - * Similar to read_some, but continues to read until all bytes in the - * supplied buffer have been read or the connection runs out of read - * requests. - * - * This method still may not read all of the bytes in the input buffer. if - * it doesn't it indicates that the connection was most likely closed or - * is in an error state where it is no longer accepting new input. - * - * @since 0.3.0 - * - * @param buf Char buffer to read into the websocket - * @param len Length of buf - * @return The number of characters from buf actually read. - */ - size_t read_all(char const * buf, size_t len) { - size_t total_read = 0; - size_t temp_read = 0; - - do { - temp_read = this->read_some_impl(buf+total_read,len-total_read); - total_read += temp_read; - } while (temp_read != 0 && total_read < len); - - return total_read; - } - - // debug stuff to invoke the async handlers - void expire_timer(lib::error_code const & ec) { - m_timer_handler(ec); - } - - void fullfil_write() { - m_write_handler(lib::error_code()); - } -protected: - /// Initialize the connection transport - /** - * Initialize the connection's transport component. - * - * @param handler The `init_handler` to call when initialization is done - */ - void init(init_handler handler) { - m_alog->write(log::alevel::devel,"debug connection init"); - handler(lib::error_code()); - } - - /// Initiate an async_read for at least num_bytes bytes into buf - /** - * Initiates an async_read request for at least num_bytes bytes. The input - * will be read into buf. A maximum of len bytes will be input. When the - * operation is complete, handler will be called with the status and number - * of bytes read. - * - * This method may or may not call handler from within the initial call. The - * application should be prepared to accept either. - * - * The application should never call this method a second time before it has - * been called back for the first read. If this is done, the second read - * will be called back immediately with a double_read error. - * - * If num_bytes or len are zero handler will be called back immediately - * indicating success. - * - * @param num_bytes Don't call handler until at least this many bytes have - * been read. - * @param buf The buffer to read bytes into - * @param len The size of buf. At maximum, this many bytes will be read. - * @param handler The callback to invoke when the operation is complete or - * ends in an error - */ - void async_read_at_least(size_t num_bytes, char * buf, size_t len, - read_handler handler) - { - std::stringstream s; - s << "debug_con async_read_at_least: " << num_bytes; - m_alog->write(log::alevel::devel,s.str()); - - if (num_bytes > len) { - handler(make_error_code(error::invalid_num_bytes),size_t(0)); - return; - } - - if (m_reading == true) { - handler(make_error_code(error::double_read),size_t(0)); - return; - } - - if (num_bytes == 0 || len == 0) { - handler(lib::error_code(),size_t(0)); - return; - } - - m_buf = buf; - m_len = len; - m_bytes_needed = num_bytes; - m_read_handler = handler; - m_cursor = 0; - m_reading = true; - } - - /// Asyncronous Transport Write - /** - * Write len bytes in buf to the output stream. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. - * - * @param buf buffer to read bytes from - * @param len number of bytes to write - * @param handler Callback to invoke with operation status. - */ - void async_write(char const *, size_t, write_handler handler) { - m_alog->write(log::alevel::devel,"debug_con async_write"); - m_write_handler = handler; - } - - /// Asyncronous Transport Write (scatter-gather) - /** - * Write a sequence of buffers to the output stream. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. - * - * @param bufs vector of buffers to write - * @param handler Callback to invoke with operation status. - */ - void async_write(std::vector const &, write_handler handler) { - m_alog->write(log::alevel::devel,"debug_con async_write buffer list"); - m_write_handler = handler; - } - - /// Set Connection Handle - /** - * @param hdl The new handle - */ - void set_handle(connection_hdl) {} - - /// Call given handler back within the transport's event system (if present) - /** - * Invoke a callback within the transport's event system if it has one. If - * it doesn't, the handler will be invoked immediately before this function - * returns. - * - * @param handler The callback to invoke - * - * @return Whether or not the transport was able to register the handler for - * callback. - */ - lib::error_code dispatch(dispatch_handler handler) { - handler(); - return lib::error_code(); - } - - /// Perform cleanup on socket shutdown_handler - /** - * @param h The `shutdown_handler` to call back when complete - */ - void async_shutdown(shutdown_handler handler) { - handler(lib::error_code()); - } - - size_t read_some_impl(char const * buf, size_t len) { - m_alog->write(log::alevel::devel,"debug_con read_some"); - - if (!m_reading) { - m_elog->write(log::elevel::devel,"write while not reading"); - return 0; - } - - size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); - - std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); - - m_cursor += bytes_to_copy; - - if (m_cursor >= m_bytes_needed) { - complete_read(lib::error_code()); - } - - return bytes_to_copy; - } - - /// Signal that a requested read is complete - /** - * Sets the reading flag to false and returns the handler that should be - * called back with the result of the read. The cursor position that is sent - * is whatever the value of m_cursor is. - * - * It MUST NOT be called when m_reading is false. - * it MUST be called while holding the read lock - * - * It is important to use this method rather than directly setting/calling - * m_read_handler back because this function makes sure to delete the - * locally stored handler which contains shared pointers that will otherwise - * cause circular reference based memory leaks. - * - * @param ec The error code to forward to the read handler - */ - void complete_read(lib::error_code const & ec) { - m_reading = false; - - read_handler handler = m_read_handler; - m_read_handler = read_handler(); - - handler(ec,m_cursor); - } -private: - timer_handler m_timer_handler; - - // Read space (Protected by m_read_mutex) - char * m_buf; - size_t m_len; - size_t m_bytes_needed; - read_handler m_read_handler; - size_t m_cursor; - - // transport resources - connection_hdl m_connection_hdl; - write_handler m_write_handler; - shutdown_handler m_shutdown_handler; - - bool m_reading; - bool const m_is_server; - bool m_is_secure; - lib::shared_ptr m_alog; - lib::shared_ptr m_elog; - std::string m_remote_endpoint; -}; - - -} // namespace debug -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP +/* + * 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_TRANSPORT_DEBUG_CON_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace debug { + +/// Empty timer class to stub out for timer functionality that stub +/// transport doesn't support +struct timer { + void cancel() {} +}; + +template +class connection : public lib::enable_shared_from_this< connection > { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// transport concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + // Concurrency policy types + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + typedef lib::shared_ptr timer_ptr; + + explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) + : m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog) + { + m_alog->write(log::alevel::devel,"debug con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return type::shared_from_this(); + } + + /// Set whether or not this connection is secure + /** + * Todo: docs + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not this connection is secure. + */ + void set_secure(bool) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } + + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * Implementation is optional and can be ignored if the transport has no + * need for this information. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + + /// Set human readable remote endpoint address + /** + * Sets the remote endpoint address returned by `get_remote_endpoint`. This + * value should be a human readable string that describes the remote + * endpoint. Typically an IP address or hostname, perhaps with a port. But + * may be something else depending on the nature of the underlying + * transport. + * + * If none is set a default is returned. + * + * @since 0.3.0-alpha4 + * + * @param value The remote endpoint address to set. + */ + void set_remote_endpoint(std::string) {} + + /// Get human readable remote endpoint address + /** + * TODO: docs + * + * This value is used in access and error logs and is available to the end + * application for including in user facing interfaces and messages. + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + return "unknown (debug transport)"; + } + + /// Get the connection handle + /** + * @return The handle for this connection. + */ + connection_hdl get_handle() const { + return connection_hdl(); + } + + /// Call back a function after a period of time. + /** + * Timers are not implemented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long, timer_handler handler) { + m_alog->write(log::alevel::devel,"debug connection set timer"); + m_timer_handler = handler; + return timer_ptr(); + } + + /// Manual input supply (read all) + /** + * Similar to read_some, but continues to read until all bytes in the + * supplied buffer have been read or the connection runs out of read + * requests. + * + * This method still may not read all of the bytes in the input buffer. if + * it doesn't it indicates that the connection was most likely closed or + * is in an error state where it is no longer accepting new input. + * + * @since 0.3.0 + * + * @param buf Char buffer to read into the websocket + * @param len Length of buf + * @return The number of characters from buf actually read. + */ + size_t read_all(char const * buf, size_t len) { + size_t total_read = 0; + size_t temp_read = 0; + + do { + temp_read = this->read_some_impl(buf+total_read,len-total_read); + total_read += temp_read; + } while (temp_read != 0 && total_read < len); + + return total_read; + } + + // debug stuff to invoke the async handlers + void expire_timer(lib::error_code const & ec) { + m_timer_handler(ec); + } + + void fullfil_write() { + m_write_handler(lib::error_code()); + } +protected: + /// Initialize the connection transport + /** + * Initialize the connection's transport component. + * + * @param handler The `init_handler` to call when initialization is done + */ + void init(init_handler handler) { + m_alog->write(log::alevel::devel,"debug connection init"); + handler(lib::error_code()); + } + + /// Initiate an async_read for at least num_bytes bytes into buf + /** + * Initiates an async_read request for at least num_bytes bytes. The input + * will be read into buf. A maximum of len bytes will be input. When the + * operation is complete, handler will be called with the status and number + * of bytes read. + * + * This method may or may not call handler from within the initial call. The + * application should be prepared to accept either. + * + * The application should never call this method a second time before it has + * been called back for the first read. If this is done, the second read + * will be called back immediately with a double_read error. + * + * If num_bytes or len are zero handler will be called back immediately + * indicating success. + * + * @param num_bytes Don't call handler until at least this many bytes have + * been read. + * @param buf The buffer to read bytes into + * @param len The size of buf. At maximum, this many bytes will be read. + * @param handler The callback to invoke when the operation is complete or + * ends in an error + */ + void async_read_at_least(size_t num_bytes, char * buf, size_t len, + read_handler handler) + { + std::stringstream s; + s << "debug_con async_read_at_least: " << num_bytes; + m_alog->write(log::alevel::devel,s.str()); + + if (num_bytes > len) { + handler(make_error_code(error::invalid_num_bytes),size_t(0)); + return; + } + + if (m_reading == true) { + handler(make_error_code(error::double_read),size_t(0)); + return; + } + + if (num_bytes == 0 || len == 0) { + handler(lib::error_code(),size_t(0)); + return; + } + + m_buf = buf; + m_len = len; + m_bytes_needed = num_bytes; + m_read_handler = handler; + m_cursor = 0; + m_reading = true; + } + + /// Asyncronous Transport Write + /** + * Write len bytes in buf to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param buf buffer to read bytes from + * @param len number of bytes to write + * @param handler Callback to invoke with operation status. + */ + void async_write(char const *, size_t, write_handler handler) { + m_alog->write(log::alevel::devel,"debug_con async_write"); + m_write_handler = handler; + } + + /// Asyncronous Transport Write (scatter-gather) + /** + * Write a sequence of buffers to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param bufs vector of buffers to write + * @param handler Callback to invoke with operation status. + */ + void async_write(std::vector const &, write_handler handler) { + m_alog->write(log::alevel::devel,"debug_con async_write buffer list"); + m_write_handler = handler; + } + + /// Set Connection Handle + /** + * @param hdl The new handle + */ + void set_handle(connection_hdl) {} + + /// Call given handler back within the transport's event system (if present) + /** + * Invoke a callback within the transport's event system if it has one. If + * it doesn't, the handler will be invoked immediately before this function + * returns. + * + * @param handler The callback to invoke + * + * @return Whether or not the transport was able to register the handler for + * callback. + */ + lib::error_code dispatch(dispatch_handler handler) { + handler(); + return lib::error_code(); + } + + /// Perform cleanup on socket shutdown_handler + /** + * @param h The `shutdown_handler` to call back when complete + */ + void async_shutdown(shutdown_handler handler) { + handler(lib::error_code()); + } + + size_t read_some_impl(char const * buf, size_t len) { + m_alog->write(log::alevel::devel,"debug_con read_some"); + + if (!m_reading) { + m_elog->write(log::elevel::devel,"write while not reading"); + return 0; + } + + size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); + + std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); + + m_cursor += bytes_to_copy; + + if (m_cursor >= m_bytes_needed) { + complete_read(lib::error_code()); + } + + return bytes_to_copy; + } + + /// Signal that a requested read is complete + /** + * Sets the reading flag to false and returns the handler that should be + * called back with the result of the read. The cursor position that is sent + * is whatever the value of m_cursor is. + * + * It MUST NOT be called when m_reading is false. + * it MUST be called while holding the read lock + * + * It is important to use this method rather than directly setting/calling + * m_read_handler back because this function makes sure to delete the + * locally stored handler which contains shared pointers that will otherwise + * cause circular reference based memory leaks. + * + * @param ec The error code to forward to the read handler + */ + void complete_read(lib::error_code const & ec) { + m_reading = false; + + read_handler handler = m_read_handler; + m_read_handler = read_handler(); + + handler(ec,m_cursor); + } +private: + timer_handler m_timer_handler; + + // Read space (Protected by m_read_mutex) + char * m_buf; + size_t m_len; + size_t m_bytes_needed; + read_handler m_read_handler; + size_t m_cursor; + + // transport resources + connection_hdl m_connection_hdl; + write_handler m_write_handler; + shutdown_handler m_shutdown_handler; + + bool m_reading; + bool const m_is_server; + bool m_is_secure; + lib::shared_ptr m_alog; + lib::shared_ptr m_elog; + std::string m_remote_endpoint; +}; + + +} // namespace debug +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/debug/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/transport/debug/endpoint.hpp index 46049bd..adc89b3 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/debug/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/debug/endpoint.hpp @@ -1,140 +1,140 @@ -/* - * 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_TRANSPORT_DEBUG_HPP -#define WEBSOCKETPP_TRANSPORT_DEBUG_HPP - -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace debug { - -template -class endpoint { -public: - /// Type of this endpoint transport component - typedef endpoint type; - /// Type of a pointer to this endpoint transport component - typedef lib::shared_ptr ptr; - - /// Type of this endpoint's concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this endpoint's error logging policy - typedef typename config::elog_type elog_type; - /// Type of this endpoint's access logging policy - typedef typename config::alog_type alog_type; - - /// Type of this endpoint transport component's associated connection - /// transport component. - typedef debug::connection transport_con_type; - /// Type of a shared pointer to this endpoint transport component's - /// associated connection transport component - typedef typename transport_con_type::ptr transport_con_ptr; - - // generate and manage our own io_service - explicit endpoint() - { - //std::cout << "transport::iostream::endpoint constructor" << std::endl; - } - - /// Set whether or not endpoint can create secure connections - /** - * TODO: docs - * - * Setting this value only indicates whether or not the endpoint is capable - * of producing and managing secure connections. Connections produced by - * this endpoint must also be individually flagged as secure if they are. - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not the endpoint can create secure connections. - */ - void set_secure(bool) {} - - /// Tests whether or not the underlying transport is secure - /** - * TODO: docs - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return false; - } -protected: - /// Initialize logging - /** - * The loggers are located in the main endpoint class. As such, the - * transport doesn't have direct access to them. This method is called - * by the endpoint constructor to allow shared logging from the transport - * component. These are raw pointers to member variables of the endpoint. - * In particular, they cannot be used in the transport constructor as they - * haven't been constructed yet, and cannot be used in the transport - * destructor as they will have been destroyed by then. - * - * @param a A pointer to the access logger to use. - * @param e A pointer to the error logger to use. - */ - void init_logging(lib::shared_ptr, lib::shared_ptr) {} - - /// Initiate a new connection - /** - * @param tcon A pointer to the transport connection component of the - * connection to connect. - * @param u A URI pointer to the URI to connect to. - * @param cb The function to call back with the results when complete. - */ - void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { - cb(lib::error_code()); - } - - /// Initialize a connection - /** - * Init is called by an endpoint once for each newly created connection. - * It's purpose is to give the transport policy the chance to perform any - * transport specific initialization that couldn't be done via the default - * constructor. - * - * @param tcon A pointer to the transport portion of the connection. - * @return A status code indicating the success or failure of the operation - */ - lib::error_code init(transport_con_ptr) { - return lib::error_code(); - } -private: - -}; - -} // namespace debug -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_DEBUG_HPP +/* + * 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_TRANSPORT_DEBUG_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_HPP + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace debug { + +template +class endpoint { +public: + /// Type of this endpoint transport component + typedef endpoint type; + /// Type of a pointer to this endpoint transport component + typedef lib::shared_ptr ptr; + + /// Type of this endpoint's concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this endpoint's error logging policy + typedef typename config::elog_type elog_type; + /// Type of this endpoint's access logging policy + typedef typename config::alog_type alog_type; + + /// Type of this endpoint transport component's associated connection + /// transport component. + typedef debug::connection transport_con_type; + /// Type of a shared pointer to this endpoint transport component's + /// associated connection transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + // generate and manage our own io_service + explicit endpoint() + { + //std::cout << "transport::iostream::endpoint constructor" << std::endl; + } + + /// Set whether or not endpoint can create secure connections + /** + * TODO: docs + * + * Setting this value only indicates whether or not the endpoint is capable + * of producing and managing secure connections. Connections produced by + * this endpoint must also be individually flagged as secure if they are. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not the endpoint can create secure connections. + */ + void set_secure(bool) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + * + * @param a A pointer to the access logger to use. + * @param e A pointer to the error logger to use. + */ + void init_logging(lib::shared_ptr, lib::shared_ptr) {} + + /// Initiate a new connection + /** + * @param tcon A pointer to the transport connection component of the + * connection to connect. + * @param u A URI pointer to the URI to connect to. + * @param cb The function to call back with the results when complete. + */ + void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { + cb(lib::error_code()); + } + + /// Initialize a connection + /** + * Init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr) { + return lib::error_code(); + } +private: + +}; + +} // namespace debug +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/iostream/base.hpp b/thirdparty/websocketpp/include/websocketpp/transport/iostream/base.hpp index caa8172..f878398 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/iostream/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/iostream/base.hpp @@ -1,133 +1,133 @@ -/* - * 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_TRANSPORT_IOSTREAM_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP - -#include -#include -#include -#include - -#include - -#include -#include - -namespace websocketpp { -namespace transport { -/// Transport policy that uses STL iostream for I/O and does not support timers -namespace iostream { - -/// The type and signature of the callback used by iostream transport to write -typedef lib::function - write_handler; - -/// The type and signature of the callback used by iostream transport to perform -/// vectored writes. -/** - * If a vectored write handler is not set the standard write handler will be - * called multiple times. - */ -typedef lib::function const - & bufs)> vector_write_handler; - -/// The type and signature of the callback used by iostream transport to signal -/// a transport shutdown. -typedef lib::function shutdown_handler; - -/// iostream 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, - - /// async_read called while another async_read was in progress - double_read, - - /// An operation that requires an output stream was attempted before - /// setting one. - output_stream_required, - - /// stream error - bad_stream -}; - -/// iostream transport error category -class category : public lib::error_category { - public: - category() {} - - char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport.iostream"; - } - - std::string message(int value) const { - switch(value) { - case general: - return "Generic iostream transport policy error"; - case invalid_num_bytes: - return "async_read_at_least call requested more bytes than buffer can store"; - case double_read: - return "Async read already in progress"; - case output_stream_required: - return "An output stream to be set before async_write can be used"; - case bad_stream: - return "A stream operation returned ios::bad"; - default: - return "Unknown"; - } - } -}; - -/// Get a reference to a static copy of the iostream transport error category -inline lib::error_category const & get_category() { - static category instance; - return instance; -} - -/// Get an error code with the given value and the iostream transport category -inline lib::error_code make_error_code(error::value e) { - return lib::error_code(static_cast(e), get_category()); -} - -} // namespace error -} // namespace iostream -} // namespace transport -} // namespace websocketpp -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP +/* + * 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_TRANSPORT_IOSTREAM_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP + +#include +#include +#include +#include + +#include + +#include +#include + +namespace websocketpp { +namespace transport { +/// Transport policy that uses STL iostream for I/O and does not support timers +namespace iostream { + +/// The type and signature of the callback used by iostream transport to write +typedef lib::function + write_handler; + +/// The type and signature of the callback used by iostream transport to perform +/// vectored writes. +/** + * If a vectored write handler is not set the standard write handler will be + * called multiple times. + */ +typedef lib::function const + & bufs)> vector_write_handler; + +/// The type and signature of the callback used by iostream transport to signal +/// a transport shutdown. +typedef lib::function shutdown_handler; + +/// iostream 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, + + /// async_read called while another async_read was in progress + double_read, + + /// An operation that requires an output stream was attempted before + /// setting one. + output_stream_required, + + /// stream error + bad_stream +}; + +/// iostream transport error category +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.iostream"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic iostream transport policy error"; + case invalid_num_bytes: + return "async_read_at_least call requested more bytes than buffer can store"; + case double_read: + return "Async read already in progress"; + case output_stream_required: + return "An output stream to be set before async_write can be used"; + case bad_stream: + return "A stream operation returned ios::bad"; + default: + return "Unknown"; + } + } +}; + +/// Get a reference to a static copy of the iostream transport error category +inline lib::error_category const & get_category() { + static category instance; + return instance; +} + +/// Get an error code with the given value and the iostream transport category +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_category()); +} + +} // namespace error +} // namespace iostream +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/iostream/connection.hpp b/thirdparty/websocketpp/include/websocketpp/transport/iostream/connection.hpp index d7290c0..899a3e2 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/iostream/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/iostream/connection.hpp @@ -1,714 +1,714 @@ -/* - * 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_TRANSPORT_IOSTREAM_CON_HPP -#define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP - -#include - -#include - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace websocketpp { -namespace transport { -namespace iostream { - -/// Empty timer class to stub out for timer functionality that iostream -/// transport doesn't support -struct timer { - void cancel() {} -}; - -template -class connection : public lib::enable_shared_from_this< connection > { -public: - /// Type of this connection transport component - typedef connection type; - /// Type of a shared pointer to this connection transport component - typedef lib::shared_ptr ptr; - - /// transport concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this transport's access logging policy - typedef typename config::alog_type alog_type; - /// Type of this transport's error logging policy - typedef typename config::elog_type elog_type; - - // Concurrency policy types - typedef typename concurrency_type::scoped_lock_type scoped_lock_type; - typedef typename concurrency_type::mutex_type mutex_type; - - typedef lib::shared_ptr timer_ptr; - - explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) - : m_output_stream(NULL) - , m_reading(false) - , m_is_server(is_server) - , m_is_secure(false) - , m_alog(alog) - , m_elog(elog) - , m_remote_endpoint("iostream transport") - { - m_alog->write(log::alevel::devel,"iostream con transport constructor"); - } - - /// Get a shared pointer to this component - ptr get_shared() { - return type::shared_from_this(); - } - - /// Register a std::ostream with the transport for writing output - /** - * Register a std::ostream with the transport. All future writes will be - * done to this output stream. - * - * @param o A pointer to the ostream to use for output. - */ - void register_ostream(std::ostream * o) { - // TODO: lock transport state? - scoped_lock_type lock(m_read_mutex); - m_output_stream = o; - } - - /// Set uri hook - /** - * Called by the endpoint as a connection is being established to provide - * the uri being connected to to the transport layer. - * - * This transport policy doesn't use the uri so it is ignored. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr) {} - - /// Overloaded stream input operator - /** - * Attempts to read input from the given stream into the transport. Bytes - * will be extracted from the input stream to fulfill any pending reads. - * Input in this manner will only read until the current read buffer has - * been filled. Then it will signal the library to process the input. If the - * library's input handler adds a new async_read, additional bytes will be - * read, otherwise the input operation will end. - * - * When this function returns one of the following conditions is true: - * - There is no outstanding read operation - * - There are no more bytes available in the input stream - * - * You can use tellg() on the input stream to determine if all of the input - * bytes were read or not. - * - * If there is no pending read operation when the input method is called, it - * will return immediately and tellg() will not have changed. - */ - friend std::istream & operator>> (std::istream & in, type & t) { - // this serializes calls to external read. - scoped_lock_type lock(t.m_read_mutex); - - t.read(in); - - return in; - } - - /// Manual input supply (read some) - /** - * Copies bytes from buf into WebSocket++'s input buffers. Bytes will be - * copied from the supplied buffer to fulfill any pending library reads. It - * will return the number of bytes successfully processed. If there are no - * pending reads read_some will return immediately. Not all of the bytes may - * be able to be read in one call. - * - * @since 0.3.0-alpha4 - * - * @param buf Char buffer to read into the websocket - * @param len Length of buf - * @return The number of characters from buf actually read. - */ - size_t read_some(char const * buf, size_t len) { - // this serializes calls to external read. - scoped_lock_type lock(m_read_mutex); - - return this->read_some_impl(buf,len); - } - - /// Manual input supply (read all) - /** - * Similar to read_some, but continues to read until all bytes in the - * supplied buffer have been read or the connection runs out of read - * requests. - * - * This method still may not read all of the bytes in the input buffer. if - * it doesn't it indicates that the connection was most likely closed or - * is in an error state where it is no longer accepting new input. - * - * @since 0.3.0 - * - * @param buf Char buffer to read into the websocket - * @param len Length of buf - * @return The number of characters from buf actually read. - */ - size_t read_all(char const * buf, size_t len) { - // this serializes calls to external read. - scoped_lock_type lock(m_read_mutex); - - size_t total_read = 0; - size_t temp_read = 0; - - do { - temp_read = this->read_some_impl(buf+total_read,len-total_read); - total_read += temp_read; - } while (temp_read != 0 && total_read < len); - - return total_read; - } - - /// Manual input supply (DEPRECATED) - /** - * @deprecated DEPRECATED in favor of read_some() - * @see read_some() - */ - size_t readsome(char const * buf, size_t len) { - return this->read_some(buf,len); - } - - /// Signal EOF - /** - * Signals to the transport that data stream being read has reached EOF and - * that no more bytes may be read or written to/from the transport. - * - * @since 0.3.0-alpha4 - */ - void eof() { - // this serializes calls to external read. - scoped_lock_type lock(m_read_mutex); - - if (m_reading) { - complete_read(make_error_code(transport::error::eof)); - } - } - - /// Signal transport error - /** - * Signals to the transport that a fatal data stream error has occurred and - * that no more bytes may be read or written to/from the transport. - * - * @since 0.3.0-alpha4 - */ - void fatal_error() { - // this serializes calls to external read. - scoped_lock_type lock(m_read_mutex); - - if (m_reading) { - complete_read(make_error_code(transport::error::pass_through)); - } - } - - /// Set whether or not this connection is secure - /** - * The iostream transport does not provide any security features. As such - * it defaults to returning false when `is_secure` is called. However, the - * iostream transport may be used to wrap an external socket API that may - * provide secure transport. This method allows that external API to flag - * whether or not this connection is secure so that users of the WebSocket++ - * API will get more accurate information. - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not this connection is secure. - */ - void set_secure(bool value) { - m_is_secure = value; - } - - /// Tests whether or not the underlying transport is secure - /** - * iostream transport will return false always because it has no information - * about the ultimate remote endpoint. This may or may not be accurate - * depending on the real source of bytes being input. The `set_secure` - * method may be used to flag connections that are secured by an external - * API - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return m_is_secure; - } - - /// Set human readable remote endpoint address - /** - * Sets the remote endpoint address returned by `get_remote_endpoint`. This - * value should be a human readable string that describes the remote - * endpoint. Typically an IP address or hostname, perhaps with a port. But - * may be something else depending on the nature of the underlying - * transport. - * - * If none is set the default is "iostream transport". - * - * @since 0.3.0-alpha4 - * - * @param value The remote endpoint address to set. - */ - void set_remote_endpoint(std::string value) { - m_remote_endpoint = value; - } - - /// Get human readable remote endpoint address - /** - * The iostream transport has no information about the ultimate remote - * endpoint. It will return the string "iostream transport". The - * `set_remote_endpoint` method may be used by external network code to set - * a more accurate value. - * - * This value is used in access and error logs and is available to the end - * application for including in user facing interfaces and messages. - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint() const { - return m_remote_endpoint; - } - - /// Get the connection handle - /** - * @return The handle for this connection. - */ - connection_hdl get_handle() const { - return m_connection_hdl; - } - - /// Call back a function after a period of time. - /** - * Timers are not implemented in this transport. The timer pointer will - * always be empty. The handler will never be called. - * - * @param duration Length of time to wait in milliseconds - * @param callback The function to call back when the timer has expired - * @return A handle that can be used to cancel the timer if it is no longer - * needed. - */ - timer_ptr set_timer(long, timer_handler) { - return timer_ptr(); - } - - /// Sets the write handler - /** - * The write handler is called when the iostream transport receives data - * that needs to be written to the appropriate output location. This handler - * can be used in place of registering an ostream for output. - * - * The signature of the handler is - * `lib::error_code (connection_hdl, char const *, size_t)` The - * code returned will be reported and logged by the core library. - * - * See also, set_vector_write_handler, for an optional write handler that - * allows more efficient handling of multiple writes at once. - * - * @see set_vector_write_handler - * - * @since 0.5.0 - * - * @param h The handler to call when data is to be written. - */ - void set_write_handler(write_handler h) { - m_write_handler = h; - } - - /// Sets the vectored write handler - /** - * The vectored write handler is called when the iostream transport receives - * multiple chunks of data that need to be written to the appropriate output - * location. This handler can be used in conjunction with the write_handler - * in place of registering an ostream for output. - * - * The sequence of buffers represents bytes that should be written - * consecutively and it is suggested to group the buffers into as few next - * layer packets as possible. Vector write is used to allow implementations - * that support it to coalesce writes into a single TCP packet or TLS - * segment for improved efficiency. - * - * This is an optional handler. If it is not defined then multiple calls - * will be made to the standard write handler. - * - * The signature of the handler is - * `lib::error_code (connection_hdl, std::vector - * const & bufs)`. The code returned will be reported and logged by the core - * library. The `websocketpp::transport::buffer` type is a struct with two - * data members. buf (char const *) and len (size_t). - * - * @since 0.6.0 - * - * @param h The handler to call when vectored data is to be written. - */ - void set_vector_write_handler(vector_write_handler h) { - m_vector_write_handler = h; - } - - /// Sets the shutdown handler - /** - * The shutdown handler is called when the iostream transport receives a - * notification from the core library that it is finished with all read and - * write operations and that the underlying transport can be cleaned up. - * - * If you are using iostream transport with another socket library, this is - * a good time to close/shutdown the socket for this connection. - * - * The signature of the handler is `lib::error_code (connection_hdl)`. The - * code returned will be reported and logged by the core library. - * - * @since 0.5.0 - * - * @param h The handler to call on connection shutdown. - */ - void set_shutdown_handler(shutdown_handler h) { - m_shutdown_handler = h; - } -protected: - /// Initialize the connection transport - /** - * Initialize the connection's transport component. - * - * @param handler The `init_handler` to call when initialization is done - */ - void init(init_handler handler) { - m_alog->write(log::alevel::devel,"iostream connection init"); - handler(lib::error_code()); - } - - /// Initiate an async_read for at least num_bytes bytes into buf - /** - * Initiates an async_read request for at least num_bytes bytes. The input - * will be read into buf. A maximum of len bytes will be input. When the - * operation is complete, handler will be called with the status and number - * of bytes read. - * - * This method may or may not call handler from within the initial call. The - * application should be prepared to accept either. - * - * The application should never call this method a second time before it has - * been called back for the first read. If this is done, the second read - * will be called back immediately with a double_read error. - * - * If num_bytes or len are zero handler will be called back immediately - * indicating success. - * - * @param num_bytes Don't call handler until at least this many bytes have - * been read. - * @param buf The buffer to read bytes into - * @param len The size of buf. At maximum, this many bytes will be read. - * @param handler The callback to invoke when the operation is complete or - * ends in an error - */ - void async_read_at_least(size_t num_bytes, char *buf, size_t len, - read_handler handler) - { - std::stringstream s; - s << "iostream_con async_read_at_least: " << num_bytes; - m_alog->write(log::alevel::devel,s.str()); - - if (num_bytes > len) { - handler(make_error_code(error::invalid_num_bytes),size_t(0)); - return; - } - - if (m_reading == true) { - handler(make_error_code(error::double_read),size_t(0)); - return; - } - - if (num_bytes == 0 || len == 0) { - handler(lib::error_code(),size_t(0)); - return; - } - - m_buf = buf; - m_len = len; - m_bytes_needed = num_bytes; - m_read_handler = handler; - m_cursor = 0; - m_reading = true; - } - - /// Asyncronous Transport Write - /** - * Write len bytes in buf to the output method. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. Other possible errors (not exhaustive) - * output_stream_required: No output stream was registered to write to - * bad_stream: a ostream pass through error - * - * This method will attempt to write to the registered ostream first. If an - * ostream is not registered it will use the write handler. If neither are - * registered then an error is passed up to the connection. - * - * @param buf buffer to read bytes from - * @param len number of bytes to write - * @param handler Callback to invoke with operation status. - */ - void async_write(char const * buf, size_t len, transport::write_handler - handler) - { - m_alog->write(log::alevel::devel,"iostream_con async_write"); - // TODO: lock transport state? - - lib::error_code ec; - - if (m_output_stream) { - m_output_stream->write(buf,len); - - if (m_output_stream->bad()) { - ec = make_error_code(error::bad_stream); - } - } else if (m_write_handler) { - ec = m_write_handler(m_connection_hdl, buf, len); - } else { - ec = make_error_code(error::output_stream_required); - } - - handler(ec); - } - - /// Asyncronous Transport Write (scatter-gather) - /** - * Write a sequence of buffers to the output method. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. Other possible errors (not exhaustive) - * output_stream_required: No output stream was registered to write to - * bad_stream: a ostream pass through error - * - * This method will attempt to write to the registered ostream first. If an - * ostream is not registered it will use the write handler. If neither are - * registered then an error is passed up to the connection. - * - * @param bufs vector of buffers to write - * @param handler Callback to invoke with operation status. - */ - void async_write(std::vector const & bufs, transport::write_handler - handler) - { - m_alog->write(log::alevel::devel,"iostream_con async_write buffer list"); - // TODO: lock transport state? - - lib::error_code ec; - - if (m_output_stream) { - std::vector::const_iterator it; - for (it = bufs.begin(); it != bufs.end(); it++) { - m_output_stream->write((*it).buf,(*it).len); - - if (m_output_stream->bad()) { - ec = make_error_code(error::bad_stream); - break; - } - } - } else if (m_vector_write_handler) { - ec = m_vector_write_handler(m_connection_hdl, bufs); - } else if (m_write_handler) { - std::vector::const_iterator it; - for (it = bufs.begin(); it != bufs.end(); it++) { - ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len); - if (ec) {break;} - } - - } else { - ec = make_error_code(error::output_stream_required); - } - - handler(ec); - } - - /// Set Connection Handle - /** - * @param hdl The new handle - */ - void set_handle(connection_hdl hdl) { - m_connection_hdl = hdl; - } - - /// Call given handler back within the transport's event system (if present) - /** - * Invoke a callback within the transport's event system if it has one. If - * it doesn't, the handler will be invoked immediately before this function - * returns. - * - * @param handler The callback to invoke - * - * @return Whether or not the transport was able to register the handler for - * callback. - */ - lib::error_code dispatch(dispatch_handler handler) { - handler(); - return lib::error_code(); - } - - /// Perform cleanup on socket shutdown_handler - /** - * If a shutdown handler is set, call it and pass through its return error - * code. Otherwise assume there is nothing to do and pass through a success - * code. - * - * @param handler The `shutdown_handler` to call back when complete - */ - void async_shutdown(transport::shutdown_handler handler) { - lib::error_code ec; - - if (m_shutdown_handler) { - ec = m_shutdown_handler(m_connection_hdl); - } - - handler(ec); - } -private: - void read(std::istream &in) { - m_alog->write(log::alevel::devel,"iostream_con read"); - - while (in.good()) { - if (!m_reading) { - m_elog->write(log::elevel::devel,"write while not reading"); - break; - } - - in.read(m_buf+m_cursor,static_cast(m_len-m_cursor)); - - if (in.gcount() == 0) { - m_elog->write(log::elevel::devel,"read zero bytes"); - break; - } - - m_cursor += static_cast(in.gcount()); - - // TODO: error handling - if (in.bad()) { - m_reading = false; - complete_read(make_error_code(error::bad_stream)); - } - - if (m_cursor >= m_bytes_needed) { - m_reading = false; - complete_read(lib::error_code()); - } - } - } - - size_t read_some_impl(char const * buf, size_t len) { - m_alog->write(log::alevel::devel,"iostream_con read_some"); - - if (!m_reading) { - m_elog->write(log::elevel::devel,"write while not reading"); - return 0; - } - - size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); - - std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); - - m_cursor += bytes_to_copy; - - if (m_cursor >= m_bytes_needed) { - complete_read(lib::error_code()); - } - - return bytes_to_copy; - } - - /// Signal that a requested read is complete - /** - * Sets the reading flag to false and returns the handler that should be - * called back with the result of the read. The cursor position that is sent - * is whatever the value of m_cursor is. - * - * It MUST NOT be called when m_reading is false. - * it MUST be called while holding the read lock - * - * It is important to use this method rather than directly setting/calling - * m_read_handler back because this function makes sure to delete the - * locally stored handler which contains shared pointers that will otherwise - * cause circular reference based memory leaks. - * - * @param ec The error code to forward to the read handler - */ - void complete_read(lib::error_code const & ec) { - m_reading = false; - - read_handler handler = m_read_handler; - m_read_handler = read_handler(); - - handler(ec,m_cursor); - } - - // Read space (Protected by m_read_mutex) - char * m_buf; - size_t m_len; - size_t m_bytes_needed; - read_handler m_read_handler; - size_t m_cursor; - - // transport resources - std::ostream * m_output_stream; - connection_hdl m_connection_hdl; - write_handler m_write_handler; - vector_write_handler m_vector_write_handler; - shutdown_handler m_shutdown_handler; - - bool m_reading; - bool const m_is_server; - bool m_is_secure; - lib::shared_ptr m_alog; - lib::shared_ptr m_elog; - std::string m_remote_endpoint; - - // This lock ensures that only one thread can edit read data for this - // connection. This is a very coarse lock that is basically locked all the - // time. The nature of the connection is such that it cannot be - // parallelized, the locking is here to prevent intra-connection concurrency - // in order to allow inter-connection concurrency. - mutex_type m_read_mutex; -}; - - -} // namespace iostream -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP +/* + * 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_TRANSPORT_IOSTREAM_CON_HPP +#define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP + +#include + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace websocketpp { +namespace transport { +namespace iostream { + +/// Empty timer class to stub out for timer functionality that iostream +/// transport doesn't support +struct timer { + void cancel() {} +}; + +template +class connection : public lib::enable_shared_from_this< connection > { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// transport concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + // Concurrency policy types + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + typedef lib::shared_ptr timer_ptr; + + explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) + : m_output_stream(NULL) + , m_reading(false) + , m_is_server(is_server) + , m_is_secure(false) + , m_alog(alog) + , m_elog(elog) + , m_remote_endpoint("iostream transport") + { + m_alog->write(log::alevel::devel,"iostream con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return type::shared_from_this(); + } + + /// Register a std::ostream with the transport for writing output + /** + * Register a std::ostream with the transport. All future writes will be + * done to this output stream. + * + * @param o A pointer to the ostream to use for output. + */ + void register_ostream(std::ostream * o) { + // TODO: lock transport state? + scoped_lock_type lock(m_read_mutex); + m_output_stream = o; + } + + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * This transport policy doesn't use the uri so it is ignored. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + + /// Overloaded stream input operator + /** + * Attempts to read input from the given stream into the transport. Bytes + * will be extracted from the input stream to fulfill any pending reads. + * Input in this manner will only read until the current read buffer has + * been filled. Then it will signal the library to process the input. If the + * library's input handler adds a new async_read, additional bytes will be + * read, otherwise the input operation will end. + * + * When this function returns one of the following conditions is true: + * - There is no outstanding read operation + * - There are no more bytes available in the input stream + * + * You can use tellg() on the input stream to determine if all of the input + * bytes were read or not. + * + * If there is no pending read operation when the input method is called, it + * will return immediately and tellg() will not have changed. + */ + friend std::istream & operator>> (std::istream & in, type & t) { + // this serializes calls to external read. + scoped_lock_type lock(t.m_read_mutex); + + t.read(in); + + return in; + } + + /// Manual input supply (read some) + /** + * Copies bytes from buf into WebSocket++'s input buffers. Bytes will be + * copied from the supplied buffer to fulfill any pending library reads. It + * will return the number of bytes successfully processed. If there are no + * pending reads read_some will return immediately. Not all of the bytes may + * be able to be read in one call. + * + * @since 0.3.0-alpha4 + * + * @param buf Char buffer to read into the websocket + * @param len Length of buf + * @return The number of characters from buf actually read. + */ + size_t read_some(char const * buf, size_t len) { + // this serializes calls to external read. + scoped_lock_type lock(m_read_mutex); + + return this->read_some_impl(buf,len); + } + + /// Manual input supply (read all) + /** + * Similar to read_some, but continues to read until all bytes in the + * supplied buffer have been read or the connection runs out of read + * requests. + * + * This method still may not read all of the bytes in the input buffer. if + * it doesn't it indicates that the connection was most likely closed or + * is in an error state where it is no longer accepting new input. + * + * @since 0.3.0 + * + * @param buf Char buffer to read into the websocket + * @param len Length of buf + * @return The number of characters from buf actually read. + */ + size_t read_all(char const * buf, size_t len) { + // this serializes calls to external read. + scoped_lock_type lock(m_read_mutex); + + size_t total_read = 0; + size_t temp_read = 0; + + do { + temp_read = this->read_some_impl(buf+total_read,len-total_read); + total_read += temp_read; + } while (temp_read != 0 && total_read < len); + + return total_read; + } + + /// Manual input supply (DEPRECATED) + /** + * @deprecated DEPRECATED in favor of read_some() + * @see read_some() + */ + size_t readsome(char const * buf, size_t len) { + return this->read_some(buf,len); + } + + /// Signal EOF + /** + * Signals to the transport that data stream being read has reached EOF and + * that no more bytes may be read or written to/from the transport. + * + * @since 0.3.0-alpha4 + */ + void eof() { + // this serializes calls to external read. + scoped_lock_type lock(m_read_mutex); + + if (m_reading) { + complete_read(make_error_code(transport::error::eof)); + } + } + + /// Signal transport error + /** + * Signals to the transport that a fatal data stream error has occurred and + * that no more bytes may be read or written to/from the transport. + * + * @since 0.3.0-alpha4 + */ + void fatal_error() { + // this serializes calls to external read. + scoped_lock_type lock(m_read_mutex); + + if (m_reading) { + complete_read(make_error_code(transport::error::pass_through)); + } + } + + /// Set whether or not this connection is secure + /** + * The iostream transport does not provide any security features. As such + * it defaults to returning false when `is_secure` is called. However, the + * iostream transport may be used to wrap an external socket API that may + * provide secure transport. This method allows that external API to flag + * whether or not this connection is secure so that users of the WebSocket++ + * API will get more accurate information. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not this connection is secure. + */ + void set_secure(bool value) { + m_is_secure = value; + } + + /// Tests whether or not the underlying transport is secure + /** + * iostream transport will return false always because it has no information + * about the ultimate remote endpoint. This may or may not be accurate + * depending on the real source of bytes being input. The `set_secure` + * method may be used to flag connections that are secured by an external + * API + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return m_is_secure; + } + + /// Set human readable remote endpoint address + /** + * Sets the remote endpoint address returned by `get_remote_endpoint`. This + * value should be a human readable string that describes the remote + * endpoint. Typically an IP address or hostname, perhaps with a port. But + * may be something else depending on the nature of the underlying + * transport. + * + * If none is set the default is "iostream transport". + * + * @since 0.3.0-alpha4 + * + * @param value The remote endpoint address to set. + */ + void set_remote_endpoint(std::string value) { + m_remote_endpoint = value; + } + + /// Get human readable remote endpoint address + /** + * The iostream transport has no information about the ultimate remote + * endpoint. It will return the string "iostream transport". The + * `set_remote_endpoint` method may be used by external network code to set + * a more accurate value. + * + * This value is used in access and error logs and is available to the end + * application for including in user facing interfaces and messages. + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + return m_remote_endpoint; + } + + /// Get the connection handle + /** + * @return The handle for this connection. + */ + connection_hdl get_handle() const { + return m_connection_hdl; + } + + /// Call back a function after a period of time. + /** + * Timers are not implemented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long, timer_handler) { + return timer_ptr(); + } + + /// Sets the write handler + /** + * The write handler is called when the iostream transport receives data + * that needs to be written to the appropriate output location. This handler + * can be used in place of registering an ostream for output. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, char const *, size_t)` The + * code returned will be reported and logged by the core library. + * + * See also, set_vector_write_handler, for an optional write handler that + * allows more efficient handling of multiple writes at once. + * + * @see set_vector_write_handler + * + * @since 0.5.0 + * + * @param h The handler to call when data is to be written. + */ + void set_write_handler(write_handler h) { + m_write_handler = h; + } + + /// Sets the vectored write handler + /** + * The vectored write handler is called when the iostream transport receives + * multiple chunks of data that need to be written to the appropriate output + * location. This handler can be used in conjunction with the write_handler + * in place of registering an ostream for output. + * + * The sequence of buffers represents bytes that should be written + * consecutively and it is suggested to group the buffers into as few next + * layer packets as possible. Vector write is used to allow implementations + * that support it to coalesce writes into a single TCP packet or TLS + * segment for improved efficiency. + * + * This is an optional handler. If it is not defined then multiple calls + * will be made to the standard write handler. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, std::vector + * const & bufs)`. The code returned will be reported and logged by the core + * library. The `websocketpp::transport::buffer` type is a struct with two + * data members. buf (char const *) and len (size_t). + * + * @since 0.6.0 + * + * @param h The handler to call when vectored data is to be written. + */ + void set_vector_write_handler(vector_write_handler h) { + m_vector_write_handler = h; + } + + /// Sets the shutdown handler + /** + * The shutdown handler is called when the iostream transport receives a + * notification from the core library that it is finished with all read and + * write operations and that the underlying transport can be cleaned up. + * + * If you are using iostream transport with another socket library, this is + * a good time to close/shutdown the socket for this connection. + * + * The signature of the handler is `lib::error_code (connection_hdl)`. The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_shutdown_handler(shutdown_handler h) { + m_shutdown_handler = h; + } +protected: + /// Initialize the connection transport + /** + * Initialize the connection's transport component. + * + * @param handler The `init_handler` to call when initialization is done + */ + void init(init_handler handler) { + m_alog->write(log::alevel::devel,"iostream connection init"); + handler(lib::error_code()); + } + + /// Initiate an async_read for at least num_bytes bytes into buf + /** + * Initiates an async_read request for at least num_bytes bytes. The input + * will be read into buf. A maximum of len bytes will be input. When the + * operation is complete, handler will be called with the status and number + * of bytes read. + * + * This method may or may not call handler from within the initial call. The + * application should be prepared to accept either. + * + * The application should never call this method a second time before it has + * been called back for the first read. If this is done, the second read + * will be called back immediately with a double_read error. + * + * If num_bytes or len are zero handler will be called back immediately + * indicating success. + * + * @param num_bytes Don't call handler until at least this many bytes have + * been read. + * @param buf The buffer to read bytes into + * @param len The size of buf. At maximum, this many bytes will be read. + * @param handler The callback to invoke when the operation is complete or + * ends in an error + */ + void async_read_at_least(size_t num_bytes, char *buf, size_t len, + read_handler handler) + { + std::stringstream s; + s << "iostream_con async_read_at_least: " << num_bytes; + m_alog->write(log::alevel::devel,s.str()); + + if (num_bytes > len) { + handler(make_error_code(error::invalid_num_bytes),size_t(0)); + return; + } + + if (m_reading == true) { + handler(make_error_code(error::double_read),size_t(0)); + return; + } + + if (num_bytes == 0 || len == 0) { + handler(lib::error_code(),size_t(0)); + return; + } + + m_buf = buf; + m_len = len; + m_bytes_needed = num_bytes; + m_read_handler = handler; + m_cursor = 0; + m_reading = true; + } + + /// Asyncronous Transport Write + /** + * Write len bytes in buf to the output method. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. Other possible errors (not exhaustive) + * output_stream_required: No output stream was registered to write to + * bad_stream: a ostream pass through error + * + * This method will attempt to write to the registered ostream first. If an + * ostream is not registered it will use the write handler. If neither are + * registered then an error is passed up to the connection. + * + * @param buf buffer to read bytes from + * @param len number of bytes to write + * @param handler Callback to invoke with operation status. + */ + void async_write(char const * buf, size_t len, transport::write_handler + handler) + { + m_alog->write(log::alevel::devel,"iostream_con async_write"); + // TODO: lock transport state? + + lib::error_code ec; + + if (m_output_stream) { + m_output_stream->write(buf,len); + + if (m_output_stream->bad()) { + ec = make_error_code(error::bad_stream); + } + } else if (m_write_handler) { + ec = m_write_handler(m_connection_hdl, buf, len); + } else { + ec = make_error_code(error::output_stream_required); + } + + handler(ec); + } + + /// Asyncronous Transport Write (scatter-gather) + /** + * Write a sequence of buffers to the output method. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. Other possible errors (not exhaustive) + * output_stream_required: No output stream was registered to write to + * bad_stream: a ostream pass through error + * + * This method will attempt to write to the registered ostream first. If an + * ostream is not registered it will use the write handler. If neither are + * registered then an error is passed up to the connection. + * + * @param bufs vector of buffers to write + * @param handler Callback to invoke with operation status. + */ + void async_write(std::vector const & bufs, transport::write_handler + handler) + { + m_alog->write(log::alevel::devel,"iostream_con async_write buffer list"); + // TODO: lock transport state? + + lib::error_code ec; + + if (m_output_stream) { + std::vector::const_iterator it; + for (it = bufs.begin(); it != bufs.end(); it++) { + m_output_stream->write((*it).buf,(*it).len); + + if (m_output_stream->bad()) { + ec = make_error_code(error::bad_stream); + break; + } + } + } else if (m_vector_write_handler) { + ec = m_vector_write_handler(m_connection_hdl, bufs); + } else if (m_write_handler) { + std::vector::const_iterator it; + for (it = bufs.begin(); it != bufs.end(); it++) { + ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len); + if (ec) {break;} + } + + } else { + ec = make_error_code(error::output_stream_required); + } + + handler(ec); + } + + /// Set Connection Handle + /** + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) { + m_connection_hdl = hdl; + } + + /// Call given handler back within the transport's event system (if present) + /** + * Invoke a callback within the transport's event system if it has one. If + * it doesn't, the handler will be invoked immediately before this function + * returns. + * + * @param handler The callback to invoke + * + * @return Whether or not the transport was able to register the handler for + * callback. + */ + lib::error_code dispatch(dispatch_handler handler) { + handler(); + return lib::error_code(); + } + + /// Perform cleanup on socket shutdown_handler + /** + * If a shutdown handler is set, call it and pass through its return error + * code. Otherwise assume there is nothing to do and pass through a success + * code. + * + * @param handler The `shutdown_handler` to call back when complete + */ + void async_shutdown(transport::shutdown_handler handler) { + lib::error_code ec; + + if (m_shutdown_handler) { + ec = m_shutdown_handler(m_connection_hdl); + } + + handler(ec); + } +private: + void read(std::istream &in) { + m_alog->write(log::alevel::devel,"iostream_con read"); + + while (in.good()) { + if (!m_reading) { + m_elog->write(log::elevel::devel,"write while not reading"); + break; + } + + in.read(m_buf+m_cursor,static_cast(m_len-m_cursor)); + + if (in.gcount() == 0) { + m_elog->write(log::elevel::devel,"read zero bytes"); + break; + } + + m_cursor += static_cast(in.gcount()); + + // TODO: error handling + if (in.bad()) { + m_reading = false; + complete_read(make_error_code(error::bad_stream)); + } + + if (m_cursor >= m_bytes_needed) { + m_reading = false; + complete_read(lib::error_code()); + } + } + } + + size_t read_some_impl(char const * buf, size_t len) { + m_alog->write(log::alevel::devel,"iostream_con read_some"); + + if (!m_reading) { + m_elog->write(log::elevel::devel,"write while not reading"); + return 0; + } + + size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); + + std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); + + m_cursor += bytes_to_copy; + + if (m_cursor >= m_bytes_needed) { + complete_read(lib::error_code()); + } + + return bytes_to_copy; + } + + /// Signal that a requested read is complete + /** + * Sets the reading flag to false and returns the handler that should be + * called back with the result of the read. The cursor position that is sent + * is whatever the value of m_cursor is. + * + * It MUST NOT be called when m_reading is false. + * it MUST be called while holding the read lock + * + * It is important to use this method rather than directly setting/calling + * m_read_handler back because this function makes sure to delete the + * locally stored handler which contains shared pointers that will otherwise + * cause circular reference based memory leaks. + * + * @param ec The error code to forward to the read handler + */ + void complete_read(lib::error_code const & ec) { + m_reading = false; + + read_handler handler = m_read_handler; + m_read_handler = read_handler(); + + handler(ec,m_cursor); + } + + // Read space (Protected by m_read_mutex) + char * m_buf; + size_t m_len; + size_t m_bytes_needed; + read_handler m_read_handler; + size_t m_cursor; + + // transport resources + std::ostream * m_output_stream; + connection_hdl m_connection_hdl; + write_handler m_write_handler; + vector_write_handler m_vector_write_handler; + shutdown_handler m_shutdown_handler; + + bool m_reading; + bool const m_is_server; + bool m_is_secure; + lib::shared_ptr m_alog; + lib::shared_ptr m_elog; + std::string m_remote_endpoint; + + // This lock ensures that only one thread can edit read data for this + // connection. This is a very coarse lock that is basically locked all the + // time. The nature of the connection is such that it cannot be + // parallelized, the locking is here to prevent intra-connection concurrency + // in order to allow inter-connection concurrency. + mutex_type m_read_mutex; +}; + + +} // namespace iostream +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/iostream/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/transport/iostream/endpoint.hpp index 14ee42a..14cba72 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/iostream/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/iostream/endpoint.hpp @@ -1,222 +1,222 @@ -/* - * 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_TRANSPORT_IOSTREAM_HPP -#define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP - -#include -#include - -#include -#include - -#include - -#include - -namespace websocketpp { -namespace transport { -namespace iostream { - -template -class endpoint { -public: - /// Type of this endpoint transport component - typedef endpoint type; - /// Type of a pointer to this endpoint transport component - typedef lib::shared_ptr ptr; - - /// Type of this endpoint's concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this endpoint's error logging policy - typedef typename config::elog_type elog_type; - /// Type of this endpoint's access logging policy - typedef typename config::alog_type alog_type; - - /// Type of this endpoint transport component's associated connection - /// transport component. - typedef iostream::connection transport_con_type; - /// Type of a shared pointer to this endpoint transport component's - /// associated connection transport component - typedef typename transport_con_type::ptr transport_con_ptr; - - // generate and manage our own io_service - explicit endpoint() : m_output_stream(NULL), m_is_secure(false) - { - //std::cout << "transport::iostream::endpoint constructor" << std::endl; - } - - /// Register a default output stream - /** - * The specified output stream will be assigned to future connections as the - * default output stream. - * - * @param o The ostream to use as the default output stream. - */ - void register_ostream(std::ostream * o) { - m_alog->write(log::alevel::devel,"register_ostream"); - m_output_stream = o; - } - - /// Set whether or not endpoint can create secure connections - /** - * The iostream transport does not provide any security features. As such - * it defaults to returning false when `is_secure` is called. However, the - * iostream transport may be used to wrap an external socket API that may - * provide secure transport. This method allows that external API to flag - * whether or not it can create secure connections so that users of the - * WebSocket++ API will get more accurate information. - * - * Setting this value only indicates whether or not the endpoint is capable - * of producing and managing secure connections. Connections produced by - * this endpoint must also be individually flagged as secure if they are. - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not the endpoint can create secure connections. - */ - void set_secure(bool value) { - m_is_secure = value; - } - - /// Tests whether or not the underlying transport is secure - /** - * iostream transport will return false by default because it has no - * information about the ultimate remote endpoint. This may or may not be - * accurate depending on the real source of bytes being input. `set_secure` - * may be used by a wrapper API to correct the return value in the case that - * secure connections are in fact possible. - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return m_is_secure; - } - - /// Sets the write handler - /** - * The write handler is called when the iostream transport receives data - * that needs to be written to the appropriate output location. This handler - * can be used in place of registering an ostream for output. - * - * The signature of the handler is - * `lib::error_code (connection_hdl, char const *, size_t)` The - * code returned will be reported and logged by the core library. - * - * @since 0.5.0 - * - * @param h The handler to call on connection shutdown. - */ - void set_write_handler(write_handler h) { - m_write_handler = h; - } - - /// Sets the shutdown handler - /** - * The shutdown handler is called when the iostream transport receives a - * notification from the core library that it is finished with all read and - * write operations and that the underlying transport can be cleaned up. - * - * If you are using iostream transport with another socket library, this is - * a good time to close/shutdown the socket for this connection. - * - * The signature of the handler is lib::error_code (connection_hdl). The - * code returned will be reported and logged by the core library. - * - * @since 0.5.0 - * - * @param h The handler to call on connection shutdown. - */ - void set_shutdown_handler(shutdown_handler h) { - m_shutdown_handler = h; - } -protected: - /// Initialize logging - /** - * The loggers are located in the main endpoint class. As such, the - * transport doesn't have direct access to them. This method is called - * by the endpoint constructor to allow shared logging from the transport - * component. These are raw pointers to member variables of the endpoint. - * In particular, they cannot be used in the transport constructor as they - * haven't been constructed yet, and cannot be used in the transport - * destructor as they will have been destroyed by then. - * - * @param a A pointer to the access logger to use. - * @param e A pointer to the error logger to use. - */ - void init_logging(lib::shared_ptr a, lib::shared_ptr e) { - m_elog = e; - m_alog = a; - } - - /// Initiate a new connection - /** - * @param tcon A pointer to the transport connection component of the - * connection to connect. - * @param u A URI pointer to the URI to connect to. - * @param cb The function to call back with the results when complete. - */ - void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { - cb(lib::error_code()); - } - - /// Initialize a connection - /** - * Init is called by an endpoint once for each newly created connection. - * It's purpose is to give the transport policy the chance to perform any - * transport specific initialization that couldn't be done via the default - * constructor. - * - * @param tcon A pointer to the transport portion of the connection. - * @return A status code indicating the success or failure of the operation - */ - lib::error_code init(transport_con_ptr tcon) { - tcon->register_ostream(m_output_stream); - if (m_shutdown_handler) { - tcon->set_shutdown_handler(m_shutdown_handler); - } - if (m_write_handler) { - tcon->set_write_handler(m_write_handler); - } - return lib::error_code(); - } -private: - std::ostream * m_output_stream; - shutdown_handler m_shutdown_handler; - write_handler m_write_handler; - - lib::shared_ptr m_elog; - lib::shared_ptr m_alog; - bool m_is_secure; -}; - - -} // namespace iostream -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP +/* + * 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_TRANSPORT_IOSTREAM_HPP +#define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP + +#include +#include + +#include +#include + +#include + +#include + +namespace websocketpp { +namespace transport { +namespace iostream { + +template +class endpoint { +public: + /// Type of this endpoint transport component + typedef endpoint type; + /// Type of a pointer to this endpoint transport component + typedef lib::shared_ptr ptr; + + /// Type of this endpoint's concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this endpoint's error logging policy + typedef typename config::elog_type elog_type; + /// Type of this endpoint's access logging policy + typedef typename config::alog_type alog_type; + + /// Type of this endpoint transport component's associated connection + /// transport component. + typedef iostream::connection transport_con_type; + /// Type of a shared pointer to this endpoint transport component's + /// associated connection transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + // generate and manage our own io_service + explicit endpoint() : m_output_stream(NULL), m_is_secure(false) + { + //std::cout << "transport::iostream::endpoint constructor" << std::endl; + } + + /// Register a default output stream + /** + * The specified output stream will be assigned to future connections as the + * default output stream. + * + * @param o The ostream to use as the default output stream. + */ + void register_ostream(std::ostream * o) { + m_alog->write(log::alevel::devel,"register_ostream"); + m_output_stream = o; + } + + /// Set whether or not endpoint can create secure connections + /** + * The iostream transport does not provide any security features. As such + * it defaults to returning false when `is_secure` is called. However, the + * iostream transport may be used to wrap an external socket API that may + * provide secure transport. This method allows that external API to flag + * whether or not it can create secure connections so that users of the + * WebSocket++ API will get more accurate information. + * + * Setting this value only indicates whether or not the endpoint is capable + * of producing and managing secure connections. Connections produced by + * this endpoint must also be individually flagged as secure if they are. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not the endpoint can create secure connections. + */ + void set_secure(bool value) { + m_is_secure = value; + } + + /// Tests whether or not the underlying transport is secure + /** + * iostream transport will return false by default because it has no + * information about the ultimate remote endpoint. This may or may not be + * accurate depending on the real source of bytes being input. `set_secure` + * may be used by a wrapper API to correct the return value in the case that + * secure connections are in fact possible. + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return m_is_secure; + } + + /// Sets the write handler + /** + * The write handler is called when the iostream transport receives data + * that needs to be written to the appropriate output location. This handler + * can be used in place of registering an ostream for output. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, char const *, size_t)` The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_write_handler(write_handler h) { + m_write_handler = h; + } + + /// Sets the shutdown handler + /** + * The shutdown handler is called when the iostream transport receives a + * notification from the core library that it is finished with all read and + * write operations and that the underlying transport can be cleaned up. + * + * If you are using iostream transport with another socket library, this is + * a good time to close/shutdown the socket for this connection. + * + * The signature of the handler is lib::error_code (connection_hdl). The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_shutdown_handler(shutdown_handler h) { + m_shutdown_handler = h; + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + * + * @param a A pointer to the access logger to use. + * @param e A pointer to the error logger to use. + */ + void init_logging(lib::shared_ptr a, lib::shared_ptr e) { + m_elog = e; + m_alog = a; + } + + /// Initiate a new connection + /** + * @param tcon A pointer to the transport connection component of the + * connection to connect. + * @param u A URI pointer to the URI to connect to. + * @param cb The function to call back with the results when complete. + */ + void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { + cb(lib::error_code()); + } + + /// Initialize a connection + /** + * Init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr tcon) { + tcon->register_ostream(m_output_stream); + if (m_shutdown_handler) { + tcon->set_shutdown_handler(m_shutdown_handler); + } + if (m_write_handler) { + tcon->set_write_handler(m_write_handler); + } + return lib::error_code(); + } +private: + std::ostream * m_output_stream; + shutdown_handler m_shutdown_handler; + write_handler m_write_handler; + + lib::shared_ptr m_elog; + lib::shared_ptr m_alog; + bool m_is_secure; +}; + + +} // namespace iostream +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/stub/base.hpp b/thirdparty/websocketpp/include/websocketpp/transport/stub/base.hpp index 51568d5..754981e 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/stub/base.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/stub/base.hpp @@ -1,95 +1,95 @@ -/* - * 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_TRANSPORT_STUB_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP - -#include -#include - -#include - -namespace websocketpp { -namespace transport { -/// Stub transport policy that has no input or output. -namespace stub { - -/// stub transport errors -namespace error { -enum value { - /// Catch-all error for transport policy errors that don't fit in other - /// categories - general = 1, - - /// not implemented - not_implemented -}; - -/// stub transport error category -class category : public lib::error_category { - public: - category() {} - - char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport.stub"; - } - - std::string message(int value) const { - switch(value) { - case general: - return "Generic stub transport policy error"; - case not_implemented: - return "feature not implemented"; - default: - return "Unknown"; - } - } -}; - -/// Get a reference to a static copy of the stub transport error category -inline lib::error_category const & get_category() { - static category instance; - return instance; -} - -/// Get an error code with the given value and the stub transport category -inline lib::error_code make_error_code(error::value e) { - return lib::error_code(static_cast(e), get_category()); -} - -} // namespace error -} // namespace stub -} // namespace transport -} // namespace websocketpp -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ -template<> struct is_error_code_enum -{ - static bool const value = true; -}; -_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ - -#endif // WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP +/* + * 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_TRANSPORT_STUB_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP + +#include +#include + +#include + +namespace websocketpp { +namespace transport { +/// Stub transport policy that has no input or output. +namespace stub { + +/// stub transport errors +namespace error { +enum value { + /// Catch-all error for transport policy errors that don't fit in other + /// categories + general = 1, + + /// not implemented + not_implemented +}; + +/// stub transport error category +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.stub"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic stub transport policy error"; + case not_implemented: + return "feature not implemented"; + default: + return "Unknown"; + } + } +}; + +/// Get a reference to a static copy of the stub transport error category +inline lib::error_category const & get_category() { + static category instance; + return instance; +} + +/// Get an error code with the given value and the stub transport category +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_category()); +} + +} // namespace error +} // namespace stub +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/stub/connection.hpp b/thirdparty/websocketpp/include/websocketpp/transport/stub/connection.hpp index 175c1c3..5bbbf0d 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/stub/connection.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/stub/connection.hpp @@ -1,286 +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_TRANSPORT_STUB_CON_HPP -#define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP - -#include - -#include - -#include - -#include -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace stub { - -/// Empty timer class to stub out for timer functionality that stub -/// transport doesn't support -struct timer { - void cancel() {} -}; - -template -class connection : public lib::enable_shared_from_this< connection > { -public: - /// Type of this connection transport component - typedef connection type; - /// Type of a shared pointer to this connection transport component - typedef lib::shared_ptr ptr; - - /// transport concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this transport's access logging policy - typedef typename config::alog_type alog_type; - /// Type of this transport's error logging policy - typedef typename config::elog_type elog_type; - - // Concurrency policy types - typedef typename concurrency_type::scoped_lock_type scoped_lock_type; - typedef typename concurrency_type::mutex_type mutex_type; - - typedef lib::shared_ptr timer_ptr; - - explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) - : m_alog(alog), m_elog(elog) - { - m_alog->write(log::alevel::devel,"stub con transport constructor"); - } - - /// Get a shared pointer to this component - ptr get_shared() { - return type::shared_from_this(); - } - - /// Set whether or not this connection is secure - /** - * Todo: docs - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not this connection is secure. - */ - void set_secure(bool value) {} - - /// Tests whether or not the underlying transport is secure - /** - * TODO: docs - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return false; - } - - /// Set uri hook - /** - * Called by the endpoint as a connection is being established to provide - * the uri being connected to to the transport layer. - * - * Implementation is optional and can be ignored if the transport has no - * need for this information. - * - * @since 0.6.0 - * - * @param u The uri to set - */ - void set_uri(uri_ptr) {} - - /// Set human readable remote endpoint address - /** - * Sets the remote endpoint address returned by `get_remote_endpoint`. This - * value should be a human readable string that describes the remote - * endpoint. Typically an IP address or hostname, perhaps with a port. But - * may be something else depending on the nature of the underlying - * transport. - * - * If none is set a default is returned. - * - * @since 0.3.0-alpha4 - * - * @param value The remote endpoint address to set. - */ - void set_remote_endpoint(std::string value) {} - - /// Get human readable remote endpoint address - /** - * TODO: docs - * - * This value is used in access and error logs and is available to the end - * application for including in user facing interfaces and messages. - * - * @return A string identifying the address of the remote endpoint - */ - std::string get_remote_endpoint() const { - return "unknown (stub transport)"; - } - - /// Get the connection handle - /** - * @return The handle for this connection. - */ - connection_hdl get_handle() const { - return connection_hdl(); - } - - /// Call back a function after a period of time. - /** - * Timers are not implemented in this transport. The timer pointer will - * always be empty. The handler will never be called. - * - * @param duration Length of time to wait in milliseconds - * @param callback The function to call back when the timer has expired - * @return A handle that can be used to cancel the timer if it is no longer - * needed. - */ - timer_ptr set_timer(long duration, timer_handler handler) { - return timer_ptr(); - } -protected: - /// Initialize the connection transport - /** - * Initialize the connection's transport component. - * - * @param handler The `init_handler` to call when initialization is done - */ - void init(init_handler handler) { - m_alog->write(log::alevel::devel,"stub connection init"); - handler(make_error_code(error::not_implemented)); - } - - /// Initiate an async_read for at least num_bytes bytes into buf - /** - * Initiates an async_read request for at least num_bytes bytes. The input - * will be read into buf. A maximum of len bytes will be input. When the - * operation is complete, handler will be called with the status and number - * of bytes read. - * - * This method may or may not call handler from within the initial call. The - * application should be prepared to accept either. - * - * The application should never call this method a second time before it has - * been called back for the first read. If this is done, the second read - * will be called back immediately with a double_read error. - * - * If num_bytes or len are zero handler will be called back immediately - * indicating success. - * - * @param num_bytes Don't call handler until at least this many bytes have - * been read. - * @param buf The buffer to read bytes into - * @param len The size of buf. At maximum, this many bytes will be read. - * @param handler The callback to invoke when the operation is complete or - * ends in an error - */ - void async_read_at_least(size_t num_bytes, char * buf, size_t len, - read_handler handler) - { - m_alog->write(log::alevel::devel, "stub_con async_read_at_least"); - handler(make_error_code(error::not_implemented), 0); - } - - /// Asyncronous Transport Write - /** - * Write len bytes in buf to the output stream. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. - * - * @param buf buffer to read bytes from - * @param len number of bytes to write - * @param handler Callback to invoke with operation status. - */ - void async_write(char const * buf, size_t len, write_handler handler) { - m_alog->write(log::alevel::devel,"stub_con async_write"); - handler(make_error_code(error::not_implemented)); - } - - /// Asyncronous Transport Write (scatter-gather) - /** - * Write a sequence of buffers to the output stream. Call handler to report - * success or failure. handler may or may not be called during async_write, - * but it must be safe for this to happen. - * - * Will return 0 on success. - * - * @param bufs vector of buffers to write - * @param handler Callback to invoke with operation status. - */ - void async_write(std::vector const & bufs, write_handler handler) { - m_alog->write(log::alevel::devel,"stub_con async_write buffer list"); - handler(make_error_code(error::not_implemented)); - } - - /// Set Connection Handle - /** - * @param hdl The new handle - */ - void set_handle(connection_hdl hdl) {} - - /// Call given handler back within the transport's event system (if present) - /** - * Invoke a callback within the transport's event system if it has one. If - * it doesn't, the handler will be invoked immediately before this function - * returns. - * - * @param handler The callback to invoke - * - * @return Whether or not the transport was able to register the handler for - * callback. - */ - lib::error_code dispatch(dispatch_handler handler) { - handler(); - return lib::error_code(); - } - - /// Perform cleanup on socket shutdown_handler - /** - * @param h The `shutdown_handler` to call back when complete - */ - void async_shutdown(shutdown_handler handler) { - handler(lib::error_code()); - } -private: - // member variables! - lib::shared_ptr m_alog; - lib::shared_ptr m_elog; -}; - - -} // namespace stub -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_STUB_CON_HPP +/* + * 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_TRANSPORT_STUB_CON_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace stub { + +/// Empty timer class to stub out for timer functionality that stub +/// transport doesn't support +struct timer { + void cancel() {} +}; + +template +class connection : public lib::enable_shared_from_this< connection > { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// transport concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + // Concurrency policy types + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + typedef lib::shared_ptr timer_ptr; + + explicit connection(bool is_server, const lib::shared_ptr & alog, const lib::shared_ptr & elog) + : m_alog(alog), m_elog(elog) + { + m_alog->write(log::alevel::devel,"stub con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return type::shared_from_this(); + } + + /// Set whether or not this connection is secure + /** + * Todo: docs + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not this connection is secure. + */ + void set_secure(bool value) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } + + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * Implementation is optional and can be ignored if the transport has no + * need for this information. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + + /// Set human readable remote endpoint address + /** + * Sets the remote endpoint address returned by `get_remote_endpoint`. This + * value should be a human readable string that describes the remote + * endpoint. Typically an IP address or hostname, perhaps with a port. But + * may be something else depending on the nature of the underlying + * transport. + * + * If none is set a default is returned. + * + * @since 0.3.0-alpha4 + * + * @param value The remote endpoint address to set. + */ + void set_remote_endpoint(std::string value) {} + + /// Get human readable remote endpoint address + /** + * TODO: docs + * + * This value is used in access and error logs and is available to the end + * application for including in user facing interfaces and messages. + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + return "unknown (stub transport)"; + } + + /// Get the connection handle + /** + * @return The handle for this connection. + */ + connection_hdl get_handle() const { + return connection_hdl(); + } + + /// Call back a function after a period of time. + /** + * Timers are not implemented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long duration, timer_handler handler) { + return timer_ptr(); + } +protected: + /// Initialize the connection transport + /** + * Initialize the connection's transport component. + * + * @param handler The `init_handler` to call when initialization is done + */ + void init(init_handler handler) { + m_alog->write(log::alevel::devel,"stub connection init"); + handler(make_error_code(error::not_implemented)); + } + + /// Initiate an async_read for at least num_bytes bytes into buf + /** + * Initiates an async_read request for at least num_bytes bytes. The input + * will be read into buf. A maximum of len bytes will be input. When the + * operation is complete, handler will be called with the status and number + * of bytes read. + * + * This method may or may not call handler from within the initial call. The + * application should be prepared to accept either. + * + * The application should never call this method a second time before it has + * been called back for the first read. If this is done, the second read + * will be called back immediately with a double_read error. + * + * If num_bytes or len are zero handler will be called back immediately + * indicating success. + * + * @param num_bytes Don't call handler until at least this many bytes have + * been read. + * @param buf The buffer to read bytes into + * @param len The size of buf. At maximum, this many bytes will be read. + * @param handler The callback to invoke when the operation is complete or + * ends in an error + */ + void async_read_at_least(size_t num_bytes, char * buf, size_t len, + read_handler handler) + { + m_alog->write(log::alevel::devel, "stub_con async_read_at_least"); + handler(make_error_code(error::not_implemented), 0); + } + + /// Asyncronous Transport Write + /** + * Write len bytes in buf to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param buf buffer to read bytes from + * @param len number of bytes to write + * @param handler Callback to invoke with operation status. + */ + void async_write(char const * buf, size_t len, write_handler handler) { + m_alog->write(log::alevel::devel,"stub_con async_write"); + handler(make_error_code(error::not_implemented)); + } + + /// Asyncronous Transport Write (scatter-gather) + /** + * Write a sequence of buffers to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param bufs vector of buffers to write + * @param handler Callback to invoke with operation status. + */ + void async_write(std::vector const & bufs, write_handler handler) { + m_alog->write(log::alevel::devel,"stub_con async_write buffer list"); + handler(make_error_code(error::not_implemented)); + } + + /// Set Connection Handle + /** + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) {} + + /// Call given handler back within the transport's event system (if present) + /** + * Invoke a callback within the transport's event system if it has one. If + * it doesn't, the handler will be invoked immediately before this function + * returns. + * + * @param handler The callback to invoke + * + * @return Whether or not the transport was able to register the handler for + * callback. + */ + lib::error_code dispatch(dispatch_handler handler) { + handler(); + return lib::error_code(); + } + + /// Perform cleanup on socket shutdown_handler + /** + * @param h The `shutdown_handler` to call back when complete + */ + void async_shutdown(shutdown_handler handler) { + handler(lib::error_code()); + } +private: + // member variables! + lib::shared_ptr m_alog; + lib::shared_ptr m_elog; +}; + + +} // namespace stub +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_STUB_CON_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/transport/stub/endpoint.hpp b/thirdparty/websocketpp/include/websocketpp/transport/stub/endpoint.hpp index d958c0f..3bbb78f 100644 --- a/thirdparty/websocketpp/include/websocketpp/transport/stub/endpoint.hpp +++ b/thirdparty/websocketpp/include/websocketpp/transport/stub/endpoint.hpp @@ -1,140 +1,140 @@ -/* - * 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_TRANSPORT_STUB_HPP -#define WEBSOCKETPP_TRANSPORT_STUB_HPP - -#include -#include - -#include -#include - -namespace websocketpp { -namespace transport { -namespace stub { - -template -class endpoint { -public: - /// Type of this endpoint transport component - typedef endpoint type; - /// Type of a pointer to this endpoint transport component - typedef lib::shared_ptr ptr; - - /// Type of this endpoint's concurrency policy - typedef typename config::concurrency_type concurrency_type; - /// Type of this endpoint's error logging policy - typedef typename config::elog_type elog_type; - /// Type of this endpoint's access logging policy - typedef typename config::alog_type alog_type; - - /// Type of this endpoint transport component's associated connection - /// transport component. - typedef stub::connection transport_con_type; - /// Type of a shared pointer to this endpoint transport component's - /// associated connection transport component - typedef typename transport_con_type::ptr transport_con_ptr; - - // generate and manage our own io_service - explicit endpoint() - { - //std::cout << "transport::iostream::endpoint constructor" << std::endl; - } - - /// Set whether or not endpoint can create secure connections - /** - * TODO: docs - * - * Setting this value only indicates whether or not the endpoint is capable - * of producing and managing secure connections. Connections produced by - * this endpoint must also be individually flagged as secure if they are. - * - * @since 0.3.0-alpha4 - * - * @param value Whether or not the endpoint can create secure connections. - */ - void set_secure(bool value) {} - - /// Tests whether or not the underlying transport is secure - /** - * TODO: docs - * - * @return Whether or not the underlying transport is secure - */ - bool is_secure() const { - return false; - } -protected: - /// Initialize logging - /** - * The loggers are located in the main endpoint class. As such, the - * transport doesn't have direct access to them. This method is called - * by the endpoint constructor to allow shared logging from the transport - * component. These are raw pointers to member variables of the endpoint. - * In particular, they cannot be used in the transport constructor as they - * haven't been constructed yet, and cannot be used in the transport - * destructor as they will have been destroyed by then. - * - * @param a A pointer to the access logger to use. - * @param e A pointer to the error logger to use. - */ - void init_logging(alog_type * a, elog_type * e) {} - - /// Initiate a new connection - /** - * @param tcon A pointer to the transport connection component of the - * connection to connect. - * @param u A URI pointer to the URI to connect to. - * @param cb The function to call back with the results when complete. - */ - void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { - cb(make_error_code(error::not_implemented)); - } - - /// Initialize a connection - /** - * Init is called by an endpoint once for each newly created connection. - * It's purpose is to give the transport policy the chance to perform any - * transport specific initialization that couldn't be done via the default - * constructor. - * - * @param tcon A pointer to the transport portion of the connection. - * @return A status code indicating the success or failure of the operation - */ - lib::error_code init(transport_con_ptr tcon) { - return make_error_code(error::not_implemented); - } -private: - -}; - -} // namespace stub -} // namespace transport -} // namespace websocketpp - -#endif // WEBSOCKETPP_TRANSPORT_STUB_HPP +/* + * 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_TRANSPORT_STUB_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_HPP + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace stub { + +template +class endpoint { +public: + /// Type of this endpoint transport component + typedef endpoint type; + /// Type of a pointer to this endpoint transport component + typedef lib::shared_ptr ptr; + + /// Type of this endpoint's concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this endpoint's error logging policy + typedef typename config::elog_type elog_type; + /// Type of this endpoint's access logging policy + typedef typename config::alog_type alog_type; + + /// Type of this endpoint transport component's associated connection + /// transport component. + typedef stub::connection transport_con_type; + /// Type of a shared pointer to this endpoint transport component's + /// associated connection transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + // generate and manage our own io_service + explicit endpoint() + { + //std::cout << "transport::iostream::endpoint constructor" << std::endl; + } + + /// Set whether or not endpoint can create secure connections + /** + * TODO: docs + * + * Setting this value only indicates whether or not the endpoint is capable + * of producing and managing secure connections. Connections produced by + * this endpoint must also be individually flagged as secure if they are. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not the endpoint can create secure connections. + */ + void set_secure(bool value) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + * + * @param a A pointer to the access logger to use. + * @param e A pointer to the error logger to use. + */ + void init_logging(alog_type * a, elog_type * e) {} + + /// Initiate a new connection + /** + * @param tcon A pointer to the transport connection component of the + * connection to connect. + * @param u A URI pointer to the URI to connect to. + * @param cb The function to call back with the results when complete. + */ + void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { + cb(make_error_code(error::not_implemented)); + } + + /// Initialize a connection + /** + * Init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr tcon) { + return make_error_code(error::not_implemented); + } +private: + +}; + +} // namespace stub +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_STUB_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/uri.hpp b/thirdparty/websocketpp/include/websocketpp/uri.hpp index 1c379e3..c0b8b0c 100644 --- a/thirdparty/websocketpp/include/websocketpp/uri.hpp +++ b/thirdparty/websocketpp/include/websocketpp/uri.hpp @@ -1,356 +1,356 @@ -/* - * 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_URI_HPP -#define WEBSOCKETPP_URI_HPP - -#include - -#include -#include - -#include -#include -#include - -namespace websocketpp { - -// TODO: figure out why this fixes horrible linking errors. - -/// Default port for ws:// -static uint16_t const uri_default_port = 80; -/// Default port for wss:// -static uint16_t const uri_default_secure_port = 443; - -class uri { -public: - explicit uri(std::string const & uri_string) : m_valid(false) { - std::string::const_iterator it; - std::string::const_iterator temp; - - int state = 0; - - it = uri_string.begin(); - size_t uri_len = uri_string.length(); - - if (uri_len >= 7 && std::equal(it,it+6,"wss://")) { - m_secure = true; - m_scheme = "wss"; - it += 6; - } else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) { - m_secure = false; - m_scheme = "ws"; - it += 5; - } else if (uri_len >= 8 && std::equal(it,it+7,"http://")) { - m_secure = false; - m_scheme = "http"; - it += 7; - } else if (uri_len >= 9 && std::equal(it,it+8,"https://")) { - m_secure = true; - m_scheme = "https"; - it += 8; - } else { - return; - } - - // extract host. - // either a host string - // an IPv4 address - // or an IPv6 address - if (*it == '[') { - ++it; - // IPv6 literal - // extract IPv6 digits until ] - - // TODO: this doesn't work on g++... not sure why - //temp = std::find(it,it2,']'); - - temp = it; - while (temp != uri_string.end()) { - if (*temp == ']') { - break; - } - ++temp; - } - - if (temp == uri_string.end()) { - return; - } else { - // validate IPv6 literal parts - // can contain numbers, a-f and A-F - m_host.append(it,temp); - } - it = temp+1; - if (it == uri_string.end()) { - state = 2; - } else if (*it == '/') { - state = 2; - ++it; - } else if (*it == ':') { - state = 1; - ++it; - } else { - // problem - return; - } - } else { - // IPv4 or hostname - // extract until : or / - while (state == 0) { - if (it == uri_string.end()) { - state = 2; - break; - } else if (*it == '/') { - state = 2; - } else if (*it == ':') { - // end hostname start port - state = 1; - } else { - m_host += *it; - } - ++it; - } - } - - // parse port - std::string port; - while (state == 1) { - if (it == uri_string.end()) { - // state is not used after this point presently. - // this should be re-enabled if it ever is needed in a future - // refactoring - //state = 3; - break; - } else if (*it == '/') { - state = 3; - } else { - port += *it; - } - ++it; - } - - lib::error_code ec; - m_port = get_port_from_string(port, ec); - - if (ec) { - return; - } - - m_resource = "/"; - m_resource.append(it,uri_string.end()); - - - m_valid = true; - } - - uri(bool secure, std::string const & host, uint16_t port, - std::string const & resource) - : m_scheme(secure ? "wss" : "ws") - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_port(port) - , m_secure(secure) - , m_valid(true) {} - - uri(bool secure, std::string const & host, std::string const & resource) - : m_scheme(secure ? "wss" : "ws") - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_port(secure ? uri_default_secure_port : uri_default_port) - , m_secure(secure) - , m_valid(true) {} - - uri(bool secure, std::string const & host, std::string const & port, - std::string const & resource) - : m_scheme(secure ? "wss" : "ws") - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_secure(secure) - { - lib::error_code ec; - m_port = get_port_from_string(port,ec); - m_valid = !ec; - } - - uri(std::string const & scheme, std::string const & host, uint16_t port, - std::string const & resource) - : m_scheme(scheme) - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_port(port) - , m_secure(scheme == "wss" || scheme == "https") - , m_valid(true) {} - - uri(std::string scheme, std::string const & host, std::string const & resource) - : m_scheme(scheme) - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port) - , m_secure(scheme == "wss" || scheme == "https") - , m_valid(true) {} - - uri(std::string const & scheme, std::string const & host, - std::string const & port, std::string const & resource) - : m_scheme(scheme) - , m_host(host) - , m_resource(resource.empty() ? "/" : resource) - , m_secure(scheme == "wss" || scheme == "https") - { - lib::error_code ec; - m_port = get_port_from_string(port,ec); - m_valid = !ec; - } - - bool get_valid() const { - return m_valid; - } - - bool get_secure() const { - return m_secure; - } - - std::string const & get_scheme() const { - return m_scheme; - } - - std::string const & get_host() const { - return m_host; - } - - std::string get_host_port() const { - if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) { - return m_host; - } else { - std::stringstream p; - p << m_host << ":" << m_port; - return p.str(); - } - } - - std::string get_authority() const { - std::stringstream p; - p << m_host << ":" << m_port; - return p.str(); - } - - uint16_t get_port() const { - return m_port; - } - - std::string get_port_str() const { - std::stringstream p; - p << m_port; - return p.str(); - } - - std::string const & get_resource() const { - return m_resource; - } - - std::string str() const { - std::stringstream s; - - s << m_scheme << "://" << m_host; - - if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) { - s << ":" << m_port; - } - - s << m_resource; - return s.str(); - } - - /// Return the query portion - /** - * Returns the query portion (after the ?) of the URI or an empty string if - * there is none. - * - * @return query portion of the URI. - */ - std::string get_query() const { - std::size_t found = m_resource.find('?'); - if (found != std::string::npos) { - return m_resource.substr(found + 1); - } else { - return ""; - } - } - - // get fragment - - // hi <3 - - // get the string representation of this URI - - //std::string base() const; // is this still needed? - - // setter methods set some or all (in the case of parse) based on the input. - // These functions throw a uri_exception on failure. - /*void set_uri(const std::string& uri); - - void set_secure(bool secure); - void set_host(const std::string& host); - void set_port(uint16_t port); - void set_port(const std::string& port); - void set_resource(const std::string& resource);*/ -private: - uint16_t get_port_from_string(std::string const & port, lib::error_code & - ec) const - { - ec = lib::error_code(); - - if (port.empty()) { - return (m_secure ? uri_default_secure_port : uri_default_port); - } - - unsigned int t_port = static_cast(atoi(port.c_str())); - - if (t_port > 65535) { - ec = error::make_error_code(error::invalid_port); - } - - if (t_port == 0) { - ec = error::make_error_code(error::invalid_port); - } - - return static_cast(t_port); - } - - std::string m_scheme; - std::string m_host; - std::string m_resource; - uint16_t m_port; - bool m_secure; - bool m_valid; -}; - -/// Pointer to a URI -typedef lib::shared_ptr uri_ptr; - -} // namespace websocketpp - -#endif // WEBSOCKETPP_URI_HPP +/* + * 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_URI_HPP +#define WEBSOCKETPP_URI_HPP + +#include + +#include +#include + +#include +#include +#include + +namespace websocketpp { + +// TODO: figure out why this fixes horrible linking errors. + +/// Default port for ws:// +static uint16_t const uri_default_port = 80; +/// Default port for wss:// +static uint16_t const uri_default_secure_port = 443; + +class uri { +public: + explicit uri(std::string const & uri_string) : m_valid(false) { + std::string::const_iterator it; + std::string::const_iterator temp; + + int state = 0; + + it = uri_string.begin(); + size_t uri_len = uri_string.length(); + + if (uri_len >= 7 && std::equal(it,it+6,"wss://")) { + m_secure = true; + m_scheme = "wss"; + it += 6; + } else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) { + m_secure = false; + m_scheme = "ws"; + it += 5; + } else if (uri_len >= 8 && std::equal(it,it+7,"http://")) { + m_secure = false; + m_scheme = "http"; + it += 7; + } else if (uri_len >= 9 && std::equal(it,it+8,"https://")) { + m_secure = true; + m_scheme = "https"; + it += 8; + } else { + return; + } + + // extract host. + // either a host string + // an IPv4 address + // or an IPv6 address + if (*it == '[') { + ++it; + // IPv6 literal + // extract IPv6 digits until ] + + // TODO: this doesn't work on g++... not sure why + //temp = std::find(it,it2,']'); + + temp = it; + while (temp != uri_string.end()) { + if (*temp == ']') { + break; + } + ++temp; + } + + if (temp == uri_string.end()) { + return; + } else { + // validate IPv6 literal parts + // can contain numbers, a-f and A-F + m_host.append(it,temp); + } + it = temp+1; + if (it == uri_string.end()) { + state = 2; + } else if (*it == '/') { + state = 2; + ++it; + } else if (*it == ':') { + state = 1; + ++it; + } else { + // problem + return; + } + } else { + // IPv4 or hostname + // extract until : or / + while (state == 0) { + if (it == uri_string.end()) { + state = 2; + break; + } else if (*it == '/') { + state = 2; + } else if (*it == ':') { + // end hostname start port + state = 1; + } else { + m_host += *it; + } + ++it; + } + } + + // parse port + std::string port; + while (state == 1) { + if (it == uri_string.end()) { + // state is not used after this point presently. + // this should be re-enabled if it ever is needed in a future + // refactoring + //state = 3; + break; + } else if (*it == '/') { + state = 3; + } else { + port += *it; + } + ++it; + } + + lib::error_code ec; + m_port = get_port_from_string(port, ec); + + if (ec) { + return; + } + + m_resource = "/"; + m_resource.append(it,uri_string.end()); + + + m_valid = true; + } + + uri(bool secure, std::string const & host, uint16_t port, + std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(port) + , m_secure(secure) + , m_valid(true) {} + + uri(bool secure, std::string const & host, std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(secure ? uri_default_secure_port : uri_default_port) + , m_secure(secure) + , m_valid(true) {} + + uri(bool secure, std::string const & host, std::string const & port, + std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_secure(secure) + { + lib::error_code ec; + m_port = get_port_from_string(port,ec); + m_valid = !ec; + } + + uri(std::string const & scheme, std::string const & host, uint16_t port, + std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(port) + , m_secure(scheme == "wss" || scheme == "https") + , m_valid(true) {} + + uri(std::string scheme, std::string const & host, std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port) + , m_secure(scheme == "wss" || scheme == "https") + , m_valid(true) {} + + uri(std::string const & scheme, std::string const & host, + std::string const & port, std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_secure(scheme == "wss" || scheme == "https") + { + lib::error_code ec; + m_port = get_port_from_string(port,ec); + m_valid = !ec; + } + + bool get_valid() const { + return m_valid; + } + + bool get_secure() const { + return m_secure; + } + + std::string const & get_scheme() const { + return m_scheme; + } + + std::string const & get_host() const { + return m_host; + } + + std::string get_host_port() const { + if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) { + return m_host; + } else { + std::stringstream p; + p << m_host << ":" << m_port; + return p.str(); + } + } + + std::string get_authority() const { + std::stringstream p; + p << m_host << ":" << m_port; + return p.str(); + } + + uint16_t get_port() const { + return m_port; + } + + std::string get_port_str() const { + std::stringstream p; + p << m_port; + return p.str(); + } + + std::string const & get_resource() const { + return m_resource; + } + + std::string str() const { + std::stringstream s; + + s << m_scheme << "://" << m_host; + + if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) { + s << ":" << m_port; + } + + s << m_resource; + return s.str(); + } + + /// Return the query portion + /** + * Returns the query portion (after the ?) of the URI or an empty string if + * there is none. + * + * @return query portion of the URI. + */ + std::string get_query() const { + std::size_t found = m_resource.find('?'); + if (found != std::string::npos) { + return m_resource.substr(found + 1); + } else { + return ""; + } + } + + // get fragment + + // hi <3 + + // get the string representation of this URI + + //std::string base() const; // is this still needed? + + // setter methods set some or all (in the case of parse) based on the input. + // These functions throw a uri_exception on failure. + /*void set_uri(const std::string& uri); + + void set_secure(bool secure); + void set_host(const std::string& host); + void set_port(uint16_t port); + void set_port(const std::string& port); + void set_resource(const std::string& resource);*/ +private: + uint16_t get_port_from_string(std::string const & port, lib::error_code & + ec) const + { + ec = lib::error_code(); + + if (port.empty()) { + return (m_secure ? uri_default_secure_port : uri_default_port); + } + + unsigned int t_port = static_cast(atoi(port.c_str())); + + if (t_port > 65535) { + ec = error::make_error_code(error::invalid_port); + } + + if (t_port == 0) { + ec = error::make_error_code(error::invalid_port); + } + + return static_cast(t_port); + } + + std::string m_scheme; + std::string m_host; + std::string m_resource; + uint16_t m_port; + bool m_secure; + bool m_valid; +}; + +/// Pointer to a URI +typedef lib::shared_ptr uri_ptr; + +} // namespace websocketpp + +#endif // WEBSOCKETPP_URI_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/utf8_validator.hpp b/thirdparty/websocketpp/include/websocketpp/utf8_validator.hpp index f71f0a2..c057da6 100644 --- a/thirdparty/websocketpp/include/websocketpp/utf8_validator.hpp +++ b/thirdparty/websocketpp/include/websocketpp/utf8_validator.hpp @@ -1,154 +1,154 @@ -/* - * The following code is adapted from code originally written by Bjoern - * Hoehrmann . See - * http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. - * - * The original license: - * - * Copyright (c) 2008-2009 Bjoern Hoehrmann - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ - -#ifndef UTF8_VALIDATOR_HPP -#define UTF8_VALIDATOR_HPP - -#include - -#include - -namespace websocketpp { -namespace utf8_validator { - -/// State that represents a valid utf8 input sequence -static unsigned int const utf8_accept = 0; -/// State that represents an invalid utf8 input sequence -static unsigned int const utf8_reject = 1; - -/// Lookup table for the UTF8 decode state machine -static uint8_t const utf8d[] = { - 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, // 00..1f - 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, // 20..3f - 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, // 40..5f - 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, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 -}; - -/// Decode the next byte of a UTF8 sequence -/** - * @param [out] state The decoder state to advance - * @param [out] codep The codepoint to fill in - * @param [in] byte The byte to input - * @return The ending state of the decode operation - */ -inline uint32_t decode(uint32_t * state, uint32_t * codep, uint8_t byte) { - uint32_t type = utf8d[byte]; - - *codep = (*state != utf8_accept) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); - - *state = utf8d[256 + *state*16 + type]; - return *state; -} - -/// Provides streaming UTF8 validation functionality -class validator { -public: - /// Construct and initialize the validator - validator() : m_state(utf8_accept),m_codepoint(0) {} - - /// Advance the state of the validator with the next input byte - /** - * @param byte The byte to advance the validation state with - * @return Whether or not the byte resulted in a validation error. - */ - bool consume (uint8_t byte) { - if (utf8_validator::decode(&m_state,&m_codepoint,byte) == utf8_reject) { - return false; - } - return true; - } - - /// Advance validator state with input from an iterator pair - /** - * @param begin Input iterator to the start of the input range - * @param end Input iterator to the end of the input range - * @return Whether or not decoding the bytes resulted in a validation error. - */ - template - bool decode (iterator_type begin, iterator_type end) { - for (iterator_type it = begin; it != end; ++it) { - unsigned int result = utf8_validator::decode( - &m_state, - &m_codepoint, - static_cast(*it) - ); - - if (result == utf8_reject) { - return false; - } - } - return true; - } - - /// Return whether the input sequence ended on a valid utf8 codepoint - /** - * @return Whether or not the input sequence ended on a valid codepoint. - */ - bool complete() { - return m_state == utf8_accept; - } - - /// Reset the validator to decode another message - void reset() { - m_state = utf8_accept; - m_codepoint = 0; - } -private: - uint32_t m_state; - uint32_t m_codepoint; -}; - -/// Validate a UTF8 string -/** - * convenience function that creates a validator, validates a complete string - * and returns the result. - */ -inline bool validate(std::string const & s) { - validator v; - if (!v.decode(s.begin(),s.end())) { - return false; - } - return v.complete(); -} - -} // namespace utf8_validator -} // namespace websocketpp - -#endif // UTF8_VALIDATOR_HPP +/* + * The following code is adapted from code originally written by Bjoern + * Hoehrmann . See + * http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. + * + * The original license: + * + * Copyright (c) 2008-2009 Bjoern Hoehrmann + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#ifndef UTF8_VALIDATOR_HPP +#define UTF8_VALIDATOR_HPP + +#include + +#include + +namespace websocketpp { +namespace utf8_validator { + +/// State that represents a valid utf8 input sequence +static unsigned int const utf8_accept = 0; +/// State that represents an invalid utf8 input sequence +static unsigned int const utf8_reject = 1; + +/// Lookup table for the UTF8 decode state machine +static uint8_t const utf8d[] = { + 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, // 00..1f + 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, // 20..3f + 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, // 40..5f + 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, // 60..7f + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df + 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef + 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff + 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 + 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 + 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 + 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 +}; + +/// Decode the next byte of a UTF8 sequence +/** + * @param [out] state The decoder state to advance + * @param [out] codep The codepoint to fill in + * @param [in] byte The byte to input + * @return The ending state of the decode operation + */ +inline uint32_t decode(uint32_t * state, uint32_t * codep, uint8_t byte) { + uint32_t type = utf8d[byte]; + + *codep = (*state != utf8_accept) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); + + *state = utf8d[256 + *state*16 + type]; + return *state; +} + +/// Provides streaming UTF8 validation functionality +class validator { +public: + /// Construct and initialize the validator + validator() : m_state(utf8_accept),m_codepoint(0) {} + + /// Advance the state of the validator with the next input byte + /** + * @param byte The byte to advance the validation state with + * @return Whether or not the byte resulted in a validation error. + */ + bool consume (uint8_t byte) { + if (utf8_validator::decode(&m_state,&m_codepoint,byte) == utf8_reject) { + return false; + } + return true; + } + + /// Advance validator state with input from an iterator pair + /** + * @param begin Input iterator to the start of the input range + * @param end Input iterator to the end of the input range + * @return Whether or not decoding the bytes resulted in a validation error. + */ + template + bool decode (iterator_type begin, iterator_type end) { + for (iterator_type it = begin; it != end; ++it) { + unsigned int result = utf8_validator::decode( + &m_state, + &m_codepoint, + static_cast(*it) + ); + + if (result == utf8_reject) { + return false; + } + } + return true; + } + + /// Return whether the input sequence ended on a valid utf8 codepoint + /** + * @return Whether or not the input sequence ended on a valid codepoint. + */ + bool complete() { + return m_state == utf8_accept; + } + + /// Reset the validator to decode another message + void reset() { + m_state = utf8_accept; + m_codepoint = 0; + } +private: + uint32_t m_state; + uint32_t m_codepoint; +}; + +/// Validate a UTF8 string +/** + * convenience function that creates a validator, validates a complete string + * and returns the result. + */ +inline bool validate(std::string const & s) { + validator v; + if (!v.decode(s.begin(),s.end())) { + return false; + } + return v.complete(); +} + +} // namespace utf8_validator +} // namespace websocketpp + +#endif // UTF8_VALIDATOR_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/utilities.hpp b/thirdparty/websocketpp/include/websocketpp/utilities.hpp index 0a48bfa..b983c9f 100644 --- a/thirdparty/websocketpp/include/websocketpp/utilities.hpp +++ b/thirdparty/websocketpp/include/websocketpp/utilities.hpp @@ -1,180 +1,180 @@ -/* - * 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_HPP -#define WEBSOCKETPP_UTILITIES_HPP - -#include - -#include -#include -#include - -namespace websocketpp { -/// Generic non-websocket specific utility functions and data structures -namespace utility { - -/// Helper functor for case insensitive find -/** - * Based on code from - * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find - * - * templated version of my_equal so it could work with both char and wchar_t - */ -template -struct my_equal { - /// Construct the functor with the given locale - /** - * @param [in] loc The locale to use for determining the case of values - */ - my_equal(std::locale const & loc ) : m_loc(loc) {} - - /// Perform a case insensitive comparison - /** - * @param ch1 The first value to compare - * @param ch2 The second value to compare - * @return Whether or not the two values are equal when both are converted - * to uppercase using the given locale. - */ - bool operator()(charT ch1, charT ch2) { - return std::toupper(ch1, m_loc) == std::toupper(ch2, m_loc); - } -private: - std::locale const & m_loc; -}; - -/// Helper less than functor for case insensitive find -/** - * Based on code from - * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find - */ -struct ci_less { - // case-independent (ci) compare_less binary function - struct nocase_compare { - bool operator() (unsigned char const & c1, unsigned char const & c2) const { - return tolower (c1) < tolower (c2); - } - }; - bool operator() (std::string const & s1, std::string const & s2) const { - return std::lexicographical_compare - (s1.begin (), s1.end (), // source range - s2.begin (), s2.end (), // dest range - nocase_compare ()); // comparison - } -}; - -/// Find substring (case insensitive) -/** - * @param [in] haystack The string to search in - * @param [in] needle The string to search for - * @param [in] loc The locale to use for determining the case of values. - * Defaults to the current locale. - * @return An iterator to the first element of the first occurrance of needle in - * haystack. If the sequence is not found, the function returns - * haystack.end() - */ -template -typename T::const_iterator ci_find_substr(T const & haystack, T const & needle, - std::locale const & loc = std::locale()) -{ - return std::search( haystack.begin(), haystack.end(), - needle.begin(), needle.end(), my_equal(loc) ); -} - -/// Find substring (case insensitive) -/** - * @todo Is this still used? This method may not make sense.. should use - * iterators or be less generic. As is it is too tightly coupled to std::string - * - * @param [in] haystack The string to search in - * @param [in] needle The string to search for as a char array of values - * @param [in] size Length of needle - * @param [in] loc The locale to use for determining the case of values. - * Defaults to the current locale. - * @return An iterator to the first element of the first occurrance of needle in - * haystack. If the sequence is not found, the function returns - * haystack.end() - */ -template -typename T::const_iterator ci_find_substr(T const & haystack, - typename T::value_type const * needle, typename T::size_type size, - std::locale const & loc = std::locale()) -{ - return std::search( haystack.begin(), haystack.end(), - needle, needle+size, my_equal(loc) ); -} - -/// Convert a string to lowercase -/** - * @param [in] in The string to convert - * @return The converted string - */ -std::string to_lower(std::string const & in); - -/// Replace all occurrances of a substring with another -/** - * @param [in] subject The string to search in - * @param [in] search The string to search for - * @param [in] replace The string to replace with - * @return A copy of `subject` with all occurances of `search` replaced with - * `replace` - */ -std::string string_replace_all(std::string subject, std::string const & search, - std::string const & replace); - -/// Convert std::string to ascii printed string of hex digits -/** - * @param [in] input The string to print - * @return A copy of `input` converted to the printable representation of the - * hex values of its data. - */ -std::string to_hex(std::string const & input); - -/// Convert byte array (uint8_t) to ascii printed string of hex digits -/** - * @param [in] input The byte array to print - * @param [in] length The length of input - * @return A copy of `input` converted to the printable representation of the - * hex values of its data. - */ -std::string to_hex(uint8_t const * input, size_t length); - -/// Convert char array to ascii printed string of hex digits -/** - * @param [in] input The char array to print - * @param [in] length The length of input - * @return A copy of `input` converted to the printable representation of the - * hex values of its data. - */ -std::string to_hex(char const * input, size_t length); - -} // namespace utility -} // namespace websocketpp - -#include - -#endif // WEBSOCKETPP_UTILITIES_HPP +/* + * 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_HPP +#define WEBSOCKETPP_UTILITIES_HPP + +#include + +#include +#include +#include + +namespace websocketpp { +/// Generic non-websocket specific utility functions and data structures +namespace utility { + +/// Helper functor for case insensitive find +/** + * Based on code from + * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find + * + * templated version of my_equal so it could work with both char and wchar_t + */ +template +struct my_equal { + /// Construct the functor with the given locale + /** + * @param [in] loc The locale to use for determining the case of values + */ + my_equal(std::locale const & loc ) : m_loc(loc) {} + + /// Perform a case insensitive comparison + /** + * @param ch1 The first value to compare + * @param ch2 The second value to compare + * @return Whether or not the two values are equal when both are converted + * to uppercase using the given locale. + */ + bool operator()(charT ch1, charT ch2) { + return std::toupper(ch1, m_loc) == std::toupper(ch2, m_loc); + } +private: + std::locale const & m_loc; +}; + +/// Helper less than functor for case insensitive find +/** + * Based on code from + * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find + */ +struct ci_less { + // case-independent (ci) compare_less binary function + struct nocase_compare { + bool operator() (unsigned char const & c1, unsigned char const & c2) const { + return tolower (c1) < tolower (c2); + } + }; + bool operator() (std::string const & s1, std::string const & s2) const { + return std::lexicographical_compare + (s1.begin (), s1.end (), // source range + s2.begin (), s2.end (), // dest range + nocase_compare ()); // comparison + } +}; + +/// Find substring (case insensitive) +/** + * @param [in] haystack The string to search in + * @param [in] needle The string to search for + * @param [in] loc The locale to use for determining the case of values. + * Defaults to the current locale. + * @return An iterator to the first element of the first occurrance of needle in + * haystack. If the sequence is not found, the function returns + * haystack.end() + */ +template +typename T::const_iterator ci_find_substr(T const & haystack, T const & needle, + std::locale const & loc = std::locale()) +{ + return std::search( haystack.begin(), haystack.end(), + needle.begin(), needle.end(), my_equal(loc) ); +} + +/// Find substring (case insensitive) +/** + * @todo Is this still used? This method may not make sense.. should use + * iterators or be less generic. As is it is too tightly coupled to std::string + * + * @param [in] haystack The string to search in + * @param [in] needle The string to search for as a char array of values + * @param [in] size Length of needle + * @param [in] loc The locale to use for determining the case of values. + * Defaults to the current locale. + * @return An iterator to the first element of the first occurrance of needle in + * haystack. If the sequence is not found, the function returns + * haystack.end() + */ +template +typename T::const_iterator ci_find_substr(T const & haystack, + typename T::value_type const * needle, typename T::size_type size, + std::locale const & loc = std::locale()) +{ + return std::search( haystack.begin(), haystack.end(), + needle, needle+size, my_equal(loc) ); +} + +/// Convert a string to lowercase +/** + * @param [in] in The string to convert + * @return The converted string + */ +std::string to_lower(std::string const & in); + +/// Replace all occurrances of a substring with another +/** + * @param [in] subject The string to search in + * @param [in] search The string to search for + * @param [in] replace The string to replace with + * @return A copy of `subject` with all occurances of `search` replaced with + * `replace` + */ +std::string string_replace_all(std::string subject, std::string const & search, + std::string const & replace); + +/// Convert std::string to ascii printed string of hex digits +/** + * @param [in] input The string to print + * @return A copy of `input` converted to the printable representation of the + * hex values of its data. + */ +std::string to_hex(std::string const & input); + +/// Convert byte array (uint8_t) to ascii printed string of hex digits +/** + * @param [in] input The byte array to print + * @param [in] length The length of input + * @return A copy of `input` converted to the printable representation of the + * hex values of its data. + */ +std::string to_hex(uint8_t const * input, size_t length); + +/// Convert char array to ascii printed string of hex digits +/** + * @param [in] input The char array to print + * @param [in] length The length of input + * @return A copy of `input` converted to the printable representation of the + * hex values of its data. + */ +std::string to_hex(char const * input, size_t length); + +} // namespace utility +} // namespace websocketpp + +#include + +#endif // WEBSOCKETPP_UTILITIES_HPP diff --git a/thirdparty/websocketpp/include/websocketpp/version.hpp b/thirdparty/websocketpp/include/websocketpp/version.hpp index 3500d84..5766546 100644 --- a/thirdparty/websocketpp/include/websocketpp/version.hpp +++ b/thirdparty/websocketpp/include/websocketpp/version.hpp @@ -1,61 +1,61 @@ -/* - * 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_VERSION_HPP -#define WEBSOCKETPP_VERSION_HPP - -/// Namespace for the WebSocket++ project -namespace websocketpp { - -/* - other places where version information is kept - - readme.md - - changelog.md - - Doxyfile - - CMakeLists.txt -*/ - -/// Library major version number -static int const major_version = 0; -/// Library minor version number -static int const minor_version = 8; -/// Library patch version number -static int const patch_version = 2; -/// Library pre-release flag -/** - * This is a textual flag indicating the type and number for pre-release - * versions (dev, alpha, beta, rc). This will be blank for release versions. - */ - -static char const prerelease_flag[] = ""; - -/// Default user agent string -static char const user_agent[] = "WebSocket++/0.8.2"; - -} // namespace websocketpp - -#endif // WEBSOCKETPP_VERSION_HPP +/* + * 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_VERSION_HPP +#define WEBSOCKETPP_VERSION_HPP + +/// Namespace for the WebSocket++ project +namespace websocketpp { + +/* + other places where version information is kept + - readme.md + - changelog.md + - Doxyfile + - CMakeLists.txt +*/ + +/// Library major version number +static int const major_version = 0; +/// Library minor version number +static int const minor_version = 8; +/// Library patch version number +static int const patch_version = 2; +/// Library pre-release flag +/** + * This is a textual flag indicating the type and number for pre-release + * versions (dev, alpha, beta, rc). This will be blank for release versions. + */ + +static char const prerelease_flag[] = ""; + +/// Default user agent string +static char const user_agent[] = "WebSocket++/0.8.2"; + +} // namespace websocketpp + +#endif // WEBSOCKETPP_VERSION_HPP diff --git a/xmake.lua b/xmake.lua index bc4a7ac..18d369a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,95 +1,95 @@ -set_project("projectx") -set_version("0.0.1") - -add_rules("mode.release", "mode.debug") -set_languages("c++17") - -add_rules("mode.release", "mode.debug") - -add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0") -add_requires("libjuice", {system = false}) - -add_defines("JUICE_STATIC") -add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR", - "ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", "ASIO_HAS_STD_CHRONO", "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY", - "ASIO_HAS_STD_SYSTEM_ERROR") - -if is_os("windows") then - add_defines("_WEBSOCKETPP_CPP11_INTERNAL_") - add_links("ws2_32", "Bcrypt") -elseif is_os("linux") then - add_links("pthread") - set_config("cxxflags", "-fPIC") -end - -add_packages("spdlog") - -includes("thirdparty") - -target("log") - set_kind("headeronly") - add_packages("spdlog") - add_headerfiles("src/log/log.h") - add_includedirs("src/log", {public = true}) - -target("common") - set_kind("headeronly") - add_includedirs("src/common", {public = true}) - -target("inih") - set_kind("static") - add_files("src/inih/ini.c", "src/inih/INIReader.cpp") - add_includedirs("src/inih", {public = true}) - -target("ice") - set_kind("static") - add_deps("log", "common", "ws") - add_packages("asio", "nlohmann_json", "libjuice") - add_files("src/ice/*.cpp") - add_includedirs("src/ws") - add_includedirs("thirdparty/libjuice/include", {public = true}) - -target("ws") - set_kind("static") - add_deps("log") - add_files("src/ws/*.cpp") - add_packages("asio") - add_includedirs("thirdparty/websocketpp/include", {public = true}) - -target("pc") - set_kind("static") - add_deps("log") - add_deps("ws", "ice", "inih", "common") - add_files("src/pc/*.cpp") - add_packages("asio", "nlohmann_json") - add_includedirs("src/ws", "src/ice") - -target("projectx") - set_kind("shared") - add_deps("log") - add_deps("ice", "ws", "pc") - add_files("src/rtc/*.cpp") - add_packages("asio", "nlohmann_json") - add_includedirs("src/rtc", "src/ice", "src/ws", "src/pc", "src/interface") - add_rules("utils.symbols.export_all", {export_classes = true}) - -- set_policy("build.merge_archive", true) - -- set_targetdir("$(projectdir)/libdrtc/lib") - -target("signal_server") - set_kind("binary") - add_deps("log", "common") - add_files("tests/signal_server/*.cpp") - add_packages("asio", "nlohmann_json", "spdlog") - add_includedirs("thirdparty/websocketpp/include") - -target("host") - set_kind("binary") - add_deps("projectx") - add_files("tests/peerconnection/host.cpp") - add_includedirs("src/interface") - -target("guest") - set_kind("binary") - add_deps("projectx") - add_files("tests/peerconnection/guest.cpp") +set_project("projectx") +set_version("0.0.1") + +add_rules("mode.release", "mode.debug") +set_languages("c++17") + +add_rules("mode.release", "mode.debug") + +add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0") +add_requires("libjuice", {system = false}) + +add_defines("JUICE_STATIC") +add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR", + "ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", "ASIO_HAS_STD_CHRONO", "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY", + "ASIO_HAS_STD_SYSTEM_ERROR") + +if is_os("windows") then + add_defines("_WEBSOCKETPP_CPP11_INTERNAL_") + add_links("ws2_32", "Bcrypt") +elseif is_os("linux") then + add_links("pthread") + set_config("cxxflags", "-fPIC") +end + +add_packages("spdlog") + +includes("thirdparty") + +target("log") + set_kind("headeronly") + add_packages("spdlog") + add_headerfiles("src/log/log.h") + add_includedirs("src/log", {public = true}) + +target("common") + set_kind("headeronly") + add_includedirs("src/common", {public = true}) + +target("inih") + set_kind("static") + add_files("src/inih/ini.c", "src/inih/INIReader.cpp") + add_includedirs("src/inih", {public = true}) + +target("ice") + set_kind("static") + add_deps("log", "common", "ws") + add_packages("asio", "nlohmann_json", "libjuice") + add_files("src/ice/*.cpp") + add_includedirs("src/ws") + add_includedirs("thirdparty/libjuice/include", {public = true}) + +target("ws") + set_kind("static") + add_deps("log") + add_files("src/ws/*.cpp") + add_packages("asio") + add_includedirs("thirdparty/websocketpp/include", {public = true}) + +target("pc") + set_kind("static") + add_deps("log") + add_deps("ws", "ice", "inih", "common") + add_files("src/pc/*.cpp") + add_packages("asio", "nlohmann_json") + add_includedirs("src/ws", "src/ice") + +target("projectx") + set_kind("shared") + add_deps("log") + add_deps("ice", "ws", "pc") + add_files("src/rtc/*.cpp") + add_packages("asio", "nlohmann_json") + add_includedirs("src/rtc", "src/ice", "src/ws", "src/pc", "src/interface") + add_rules("utils.symbols.export_all", {export_classes = true}) + -- set_policy("build.merge_archive", true) + -- set_targetdir("$(projectdir)/libdrtc/lib") + +target("signal_server") + set_kind("binary") + add_deps("log", "common") + add_files("tests/signal_server/*.cpp") + add_packages("asio", "nlohmann_json", "spdlog") + add_includedirs("thirdparty/websocketpp/include") + +target("host") + set_kind("binary") + add_deps("projectx") + add_files("tests/peerconnection/host.cpp") + add_includedirs("src/interface") + +target("guest") + set_kind("binary") + add_deps("projectx") + add_files("tests/peerconnection/guest.cpp") add_includedirs("src/interface") \ No newline at end of file