diff --git a/examples/echo_server/echo_server.cpp b/examples/echo_server/echo_server.cpp index 0e694f69e6..a4a1811172 100644 --- a/examples/echo_server/echo_server.cpp +++ b/examples/echo_server/echo_server.cpp @@ -38,18 +38,6 @@ public: typedef echo_server_handler type; typedef plain_endpoint_type::connection_ptr connection_ptr; - void validate(connection_ptr connection) { - //std::cout << "state: " << connection->get_state() << std::endl; - } - - void on_open(connection_ptr connection) { - //std::cout << "connection opened" << std::endl; - } - - void on_close(connection_ptr connection) { - //std::cout << "connection closed" << std::endl; - } - void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) { //std::cout << "got message: " << *msg << std::endl; connection->send(msg->get_payload(),(msg->get_opcode() == websocketpp::frame::opcode::BINARY)); diff --git a/src/roles/client.hpp b/src/roles/client.hpp index 60fd706e1e..603796303a 100644 --- a/src/roles/client.hpp +++ b/src/roles/client.hpp @@ -29,6 +29,7 @@ #define WEBSOCKETPP_ROLE_CLIENT_HPP #include "../endpoint.hpp" +#include "../uri.hpp" #include #include @@ -36,6 +37,8 @@ #include +using boost::asio::ip::tcp; + namespace websocketpp { namespace role { @@ -48,48 +51,159 @@ public: public: typedef connection type; typedef endpoint endpoint_type; - - connection(endpoint& e) : m_endpoint(e) {} + protected: + connection(endpoint& e) : m_endpoint(e) {} + void async_init() { + write_request(); + } + + void write_request() { + // async write to handle_write + } + + void handle_write_request(const boost::system::error_code& error) { + if (error) { + m_endpoint.elog().at(log::elevel::ERROR) << "Error writing WebSocket request. code: " << error << log::endl; + m_connection.terminate(false); + return; + + } + + read_request(); + } + + void read_request() { + boost::asio::async_read_until( + m_connection.get_socket(), + m_connection.buffer(), + "\r\n\r\n", + boost::bind( + &type::handle_read_request, + m_connection.shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred + ) + ); + } + + // + void handle_read_request(const boost::system::error_code& error, + std::size_t bytes_transferred) + { + if (error) { + m_endpoint.elog().at(log::elevel::ERROR) << "Error reading HTTP request. code: " << error << log::endl; + m_connection.terminate(false); + return; + } + + // read + + + // start session loop + } private: endpoint& m_endpoint; connection_type& m_connection; }; - // handler interface callback class - class handler { - virtual void on_action() = 0; - }; - - typedef boost::shared_ptr handler_ptr; - // types typedef client type; typedef endpoint endpoint_type; + typedef typename endpoint_traits::connection_ptr connection_ptr; + typedef typename endpoint_traits::handler_ptr handler_ptr; - client (boost::asio::io_service& m,handler_ptr h) - : m_endpoint(static_cast< endpoint_type& >(*this)), - m_handler(h), - m_io_service(m) {} + // handler interface callback class + class handler_interface { + public: + // Required + virtual void on_open(connection_ptr connection) {}; + virtual void on_close(connection_ptr connection) {}; + virtual void on_fail(connection_ptr connection) {} + + virtual void on_message(connection_ptr connection,message::data_ptr) {}; + + // Optional + virtual bool on_ping(connection_ptr connection,std::string) {return true;} + virtual void on_pong(connection_ptr connection,std::string) {} + + }; - void connect() { - static_cast< endpoint_type* >(this)->start(); + client (boost::asio::io_service& m) + : m_state(UNINITIALIZED), + m_endpoint(static_cast< endpoint_type& >(*this)), + m_io_service(m), + m_resolver(m) {} + + connection_ptr connect(const std::string& u) { + // TODO: will throw, should we catch and wrap? + uri location(u); + + if (location.get_secure() && !m_endpoint.is_secure()) { + // TODO: what kind of exception does client throw? + throw ""; + } + + tcp::resolver::query query(location.get_host(),location.get_port_str()); + tcp::resolver::iterator iterator = m_resolver.resolve(query); + + connection_ptr con = m_endpoint.create_connection(); + + boost::asio::async_connect( + con->get_raw_socket(), + iterator, + boost::bind( + &endpoint_type::handle_connect, + endpoint_type::shared_from_this(), + con, + boost::asio::placeholders::error + ) + ); + m_state = CONNECTING; + + return con; } + // TODO: add a `perpetual` option + void run() { + m_io_service.run(); + } + + void reset() { + m_io_service.reset(); + } protected: bool is_server() { return false; } - - handler_ptr get_handler() { - return m_handler; - } private: + enum state { + UNINITIALIZED = 0, + INITIALIZED = 1, + CONNECTING = 2, + CONNECTED = 3 + }; + + void handle_connect(connection_ptr con, const boost::system::error_code& error) { + if (!error) { + m_endpoint.alog().at(log::alevel::CONNECT) << "Successful connection" << log::endl; + + m_state = CONNECTED; + con->start(); + } else { + m_endpoint.elog().at(log::elevel::ERROR) << "An error occurred while establishing a connection: " << error << log::endl; + + // TODO: fix + throw "client error"; + } + } + + state m_state; endpoint_type& m_endpoint; - handler_ptr m_handler; boost::asio::io_service& m_io_service; + tcp::resolver m_resolver; }; diff --git a/src/roles/server.hpp b/src/roles/server.hpp index 372dd9b86f..b1121a2fac 100644 --- a/src/roles/server.hpp +++ b/src/roles/server.hpp @@ -389,18 +389,16 @@ public: // handler interface callback class class handler_interface { public: - // Required - virtual void validate(connection_ptr connection) = 0; - virtual void on_open(connection_ptr connection) = 0; - virtual void on_close(connection_ptr connection) = 0; + virtual void validate(connection_ptr connection) {}; + virtual void on_open(connection_ptr connection) {}; + virtual void on_close(connection_ptr connection) {}; + virtual void on_fail(connection_ptr connection) {} - virtual void on_message(connection_ptr connection,message::data_ptr) = 0; + virtual void on_message(connection_ptr connection,message::data_ptr) {}; - // Optional virtual bool on_ping(connection_ptr connection,std::string) {return true;} virtual void on_pong(connection_ptr connection,std::string) {} virtual void http(connection_ptr connection) {} - virtual void on_fail(connection_ptr connection) {} }; server(boost::asio::io_service& m) diff --git a/websocketpp.xcodeproj/project.pbxproj b/websocketpp.xcodeproj/project.pbxproj index 4ee9ac78e5..fc081ecdcf 100644 --- a/websocketpp.xcodeproj/project.pbxproj +++ b/websocketpp.xcodeproj/project.pbxproj @@ -171,6 +171,24 @@ B663885F1487FE6C00DDAE13 /* data.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = data.hpp; path = src/messages/data.hpp; sourceTree = ""; }; B66388601487FE6C00DDAE13 /* control.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = control.hpp; path = src/messages/control.hpp; sourceTree = ""; }; B6727428148517180029CF3E /* uri.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = uri.cpp; path = src/uri.cpp; sourceTree = ""; }; + B6732435148E543000FC2B04 /* connection_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = connection_handler.hpp; sourceTree = ""; }; + B6732436148E543000FC2B04 /* frame_parser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = frame_parser.hpp; sourceTree = ""; }; + B6732437148E543000FC2B04 /* session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = session.hpp; sourceTree = ""; }; + B6732438148E543000FC2B04 /* policy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = policy.cpp; sourceTree = ""; }; + B6732439148E543000FC2B04 /* session_handler_interface.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = session_handler_interface.hpp; sourceTree = ""; }; + B673243A148E543000FC2B04 /* websocket_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_client.cpp; sourceTree = ""; }; + B673243B148E543000FC2B04 /* websocket_client.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_client.hpp; sourceTree = ""; }; + B673243C148E543000FC2B04 /* websocket_client_session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_client_session.cpp; sourceTree = ""; }; + B673243D148E543000FC2B04 /* websocket_client_session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_client_session.hpp; sourceTree = ""; }; + B673243E148E543000FC2B04 /* websocket_connection_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_connection_handler.hpp; sourceTree = ""; }; + B673243F148E543000FC2B04 /* websocket_endpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_endpoint.hpp; sourceTree = ""; }; + B6732440148E543000FC2B04 /* websocket_frame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_frame.cpp; sourceTree = ""; }; + B6732441148E543000FC2B04 /* websocket_server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_server.cpp; sourceTree = ""; }; + B6732442148E543000FC2B04 /* websocket_server.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_server.hpp; sourceTree = ""; }; + B6732443148E543000FC2B04 /* websocket_server_session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_server_session.cpp; sourceTree = ""; }; + B6732444148E543000FC2B04 /* websocket_server_session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_server_session.hpp; sourceTree = ""; }; + B6732445148E543000FC2B04 /* websocket_session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = websocket_session.cpp; sourceTree = ""; }; + B6732446148E543000FC2B04 /* websocket_session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = websocket_session.hpp; sourceTree = ""; }; B6828875143745DA002BA48B /* chat_client_handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client_handler.cpp; path = examples/chat_client/chat_client_handler.cpp; sourceTree = ""; }; B6828876143745DA002BA48B /* chat_client_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = chat_client_handler.hpp; path = examples/chat_client/chat_client_handler.hpp; sourceTree = ""; }; B6828877143745DA002BA48B /* chat_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client.cpp; path = examples/chat_client/chat_client.cpp; sourceTree = ""; }; @@ -355,6 +373,40 @@ name = messages; sourceTree = ""; }; + B6732433148E543000FC2B04 /* legacy */ = { + isa = PBXGroup; + children = ( + B6732434148E543000FC2B04 /* interfaces */, + B6732438148E543000FC2B04 /* policy.cpp */, + B6732439148E543000FC2B04 /* session_handler_interface.hpp */, + B673243A148E543000FC2B04 /* websocket_client.cpp */, + B673243B148E543000FC2B04 /* websocket_client.hpp */, + B673243C148E543000FC2B04 /* websocket_client_session.cpp */, + B673243D148E543000FC2B04 /* websocket_client_session.hpp */, + B673243E148E543000FC2B04 /* websocket_connection_handler.hpp */, + B673243F148E543000FC2B04 /* websocket_endpoint.hpp */, + B6732440148E543000FC2B04 /* websocket_frame.cpp */, + B6732441148E543000FC2B04 /* websocket_server.cpp */, + B6732442148E543000FC2B04 /* websocket_server.hpp */, + B6732443148E543000FC2B04 /* websocket_server_session.cpp */, + B6732444148E543000FC2B04 /* websocket_server_session.hpp */, + B6732445148E543000FC2B04 /* websocket_session.cpp */, + B6732446148E543000FC2B04 /* websocket_session.hpp */, + ); + name = legacy; + path = src/legacy; + sourceTree = ""; + }; + B6732434148E543000FC2B04 /* interfaces */ = { + isa = PBXGroup; + children = ( + B6732435148E543000FC2B04 /* connection_handler.hpp */, + B6732436148E543000FC2B04 /* frame_parser.hpp */, + B6732437148E543000FC2B04 /* session.hpp */, + ); + path = interfaces; + sourceTree = ""; + }; B6CF18121437C370009295BE /* echo_client */ = { isa = PBXGroup; children = ( @@ -404,6 +456,7 @@ B6DF1C7F1434ABB70029A1B1 /* src */ = { isa = PBXGroup; children = ( + B6732433148E543000FC2B04 /* legacy */, B62A5A541473EBB9005F9EB0 /* roles */, B62A5A551473EBC4005F9EB0 /* sockets */, B61387B51462B34400ED9B19 /* logger */,