13 #include <boost/thread.hpp> 16 #ifndef HAVE_BOOST_LOCK_GUARD 30 m_pMutex(mutex), m_bLocked(false)
42 pthread_mutex_unlock(m_pMutex);
50 pthread_mutex_lock(m_pMutex);
60 pthread_mutex_unlock(m_pMutex);
63 pthread_mutex_t *m_pMutex;
90 send(data, frame::opcode::TEXT);
98 send(data, frame::opcode::BINARY);
108 virtual void on_message(std::string header, std::string data) = 0;
109 virtual void on_close() = 0;
110 virtual bool on_ping(
const std::string & data) = 0;
111 virtual void on_pong(
const std::string & data) = 0;
112 virtual void do_response(
const std::string & data) = 0;
114 void send(
const std::string& payload, frame::opcode::value op);
141 , m_state(session::state::OPEN)
145 #ifndef HAVE_BOOST_LOCK_GUARD 146 pthread_mutexattr_t mattr;
147 pthread_mutexattr_init(&mattr);
148 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
149 pthread_mutex_init(&m_lock, &mattr);
150 pthread_mutexattr_destroy(&mattr);
152 m_handler->m_endpoint =
this;
155 #ifndef HAVE_BOOST_LOCK_GUARD 156 ~
wsendpoint() { pthread_mutex_destroy(&m_lock); }
172 std::istringstream s(data);
173 while (m_state != session::state::CLOSED && s.rdbuf()->in_avail()) {
176 if (m_parser.ready()) {
177 if (m_parser.is_control()) {
185 if (m_parser.ready()) {
189 case tracing::wserror::PROTOCOL_VIOLATION:
190 send_close(close::status::PROTOCOL_ERROR,e.
what());
192 case tracing::wserror::PAYLOAD_VIOLATION:
193 send_close(close::status::INVALID_PAYLOAD,e.
what());
195 case tracing::wserror::INTERNAL_ENDPOINT_ERROR:
196 send_close(close::status::INTERNAL_ENDPOINT_ERROR,e.
what());
198 case tracing::wserror::SOFT_ERROR:
200 case tracing::wserror::MESSAGE_TOO_BIG:
201 send_close(close::status::MESSAGE_TOO_BIG,e.
what());
203 case tracing::wserror::OUT_OF_MESSAGES:
213 <<
"Dropping TCP due to unrecoverable exception: " << e.
code()
214 <<
" (" << e.
what() <<
")" << std::endl;
229 void send(
const std::string& payload, frame::opcode::value op) {
238 m_handler->do_response(tmp);
242 void process_data() {
243 m_handler->on_message(m_parser.get_header_str(), m_parser.get_payload_str());
258 #ifdef HAVE_BOOST_LOCK_GUARD 259 boost::lock_guard<boost::recursive_mutex> lock(m_lock);
265 if (m_state == session::state::CLOSED) {
return;}
267 m_state = session::state::CLOSED;
268 m_handler->on_close();
283 void pong(
const std::vector<unsigned char> & payload) {
284 #ifdef HAVE_BOOST_LOCK_GUARD 285 boost::lock_guard<boost::recursive_mutex> lock(m_lock);
291 if (m_state != session::state::OPEN) {
return;}
304 m_handler->do_response(tmp);
319 void send_close(close::status::value code,
const std::string& reason) {
320 #ifdef HAVE_BOOST_LOCK_GUARD 321 boost::lock_guard<boost::recursive_mutex> lock(m_lock);
329 if (m_state != session::state::OPEN) {
330 std::cerr <<
"Tried to disconnect a session that wasn't open" << std::endl;
334 if (close::status::invalid(code)) {
335 std::cerr <<
"Tried to close a connection with invalid close code: " 336 << code << std::endl;
338 }
else if (close::status::reserved(code)) {
339 std::cerr <<
"Tried to close a connection with reserved close code: " 340 << code << std::endl;
344 m_state = session::state::CLOSING;
350 if (code != close::status::NO_STATUS) {
351 const uint16_t payload = htons(code);
352 std::string pl(reinterpret_cast<const char*>(&payload), 2);
359 m_handler->do_response(tmp);
368 void send_close_ack(close::status::value remote_close_code, std::string remote_close_reason) {
369 close::status::value local_close_code;
370 std::string local_close_reason;
372 if (remote_close_code == close::status::NO_STATUS) {
373 local_close_code = close::status::NORMAL;
374 local_close_reason =
"";
375 }
else if (remote_close_code == close::status::ABNORMAL_CLOSE) {
379 throw "shouldn't be here";
380 }
else if (close::status::invalid(remote_close_code)) {
382 local_close_code = close::status::PROTOCOL_ERROR;
383 local_close_reason =
"Status code is invalid";
384 }
else if (close::status::reserved(remote_close_code)) {
386 local_close_code = close::status::PROTOCOL_ERROR;
387 local_close_reason =
"Status code is reserved";
389 local_close_code = remote_close_code;
390 local_close_reason = remote_close_reason;
402 if (local_close_code != close::status::NO_STATUS) {
403 const uint16_t payload = htons(local_close_code);
404 std::string pl(reinterpret_cast<const char*>(&payload), 2);
405 pl.append(local_close_reason);
411 m_handler->do_response(tmp);
415 void process_control() {
416 switch (m_parser.get_opcode()) {
417 case frame::opcode::PING:
418 if (m_handler->on_ping(m_parser.get_payload_str())) {
419 pong(m_parser.get_payload());
422 case frame::opcode::PONG:
423 m_handler->on_pong(m_parser.get_payload_str());
425 case frame::opcode::CLOSE:
427 if (m_state == session::state::OPEN) {
429 std::cerr <<
"sending close ack" << std::endl;
432 send_close_ack(m_parser.get_close_code(), m_parser.get_close_reason());
433 }
else if (m_state == session::state::CLOSING) {
435 std::cerr <<
"got close ack" << std::endl;
441 tracing::wserror::PROTOCOL_VIOLATION);
449 session::state::value m_state;
450 #ifdef HAVE_BOOST_LOCK_GUARD 451 mutable boost::recursive_mutex m_lock;
453 mutable pthread_mutex_t m_lock;
458 void wshandler::send(
const std::string& payload, frame::opcode::value op)
461 m_endpoint->send(payload, op);
void send_binary(const std::string &data)
Send a binary message to the remote client.
void Unlock()
Unlocks the associated mutex.
void set_payload(const std::string &source)
Set the payload of the current message.
virtual ~wshandler()
Destructor.
Automatically unlocks a mutex if destroyed.
void send(const std::string &payload, frame::opcode::value op)
Send a data message.
std::string get_payload_str() const
Retrieves payload.
The main parser/codec for our WebSockets implementation.
MutexHelper(pthread_mutex_t *mutex, bool locknow=true)
Constructs a new instance.
~MutexHelper()
Unlocks the associated mutex.
virtual int code() const
Retrieve error code.
void AddRxData(std::string data)
Processes incoming data from the client.
A VERY simplistic random generator.
void set_fin(bool fin)
Set the FIN bit of the current message.
std::string get_header_str()
Retrieves header.
wsendpoint(wshandler *h)
Constructor.
This class implements a server-side WebSockets endpoint.
This class represents any errors in our WebSockets implementation.
virtual const char * what() const
Retrieve error message.
void set_masked(bool masked)
Set the MASKED bit of the current message.
void Lock()
Locks the associated mutex.
void send_text(const std::string &data)
Send a text message to the remote client.
void set_opcode(opcode::value op)
Set the opcode of the current message.
Event handler interface for the server-side WebSockets endpoint.