diff --git a/API.md b/API.md index 1061fc74..4cc16460 100644 --- a/API.md +++ b/API.md @@ -91,6 +91,16 @@ Get current namespace name which the client is inside. #### Constructors `client()` default constructor. +`client(const std::string& uri)` + +Constructor with URI. This form of the constructor will select automatically +between TLS and non-TLS versions of the client if you are linking with the +TLS build. To use TLS, provide a URI with the `https://` or `wss://` scheme, +otherwise use 'http://' or 'ws://'. If an unsupported scheme is given, an +exception will be thrown. + +After constructing with this URI, you may call `connect()` with no arguments. + #### Connection Listeners `void set_open_listener(con_listener const& l)` @@ -130,6 +140,10 @@ Set listener for socket close event, called when any sockets being closed, after ``` #### Connect and Close +`void connect()` + +Connect to socket.io server URI previously given to the constructor. + `void connect(const std::string& uri)` Connect to socket.io server, e.g., `client.connect("ws://localhost:3000");` diff --git a/src/internal/sio_client_impl.cpp b/src/internal/sio_client_impl.cpp index 618dd1f4..8da8b8c6 100644 --- a/src/internal/sio_client_impl.cpp +++ b/src/internal/sio_client_impl.cpp @@ -9,6 +9,7 @@ #include "sio_client_impl.h" #include #include +#include #include #include // Comment this out to disable handshake logging to stdout @@ -24,7 +25,9 @@ using namespace std; namespace sio { /*************************public:*************************/ - client_impl::client_impl() : + template + client_impl::client_impl(const string& uri) : + m_base_url(uri), m_con_state(con_closed), m_ping_interval(0), m_ping_timeout(0), @@ -45,25 +48,24 @@ namespace sio // Bind the clients we are using using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; - m_client.set_open_handler(lib::bind(&client_impl::on_open,this,_1)); - m_client.set_close_handler(lib::bind(&client_impl::on_close,this,_1)); - m_client.set_fail_handler(lib::bind(&client_impl::on_fail,this,_1)); - m_client.set_message_handler(lib::bind(&client_impl::on_message,this,_1,_2)); -#if SIO_TLS - m_client.set_tls_init_handler(lib::bind(&client_impl::on_tls_init,this,_1)); -#endif - m_packet_mgr.set_decode_callback(lib::bind(&client_impl::on_decode,this,_1)); - - m_packet_mgr.set_encode_callback(lib::bind(&client_impl::on_encode,this,_1,_2)); + m_client.set_open_handler(lib::bind(&client_impl::on_open,this,_1)); + m_client.set_close_handler(lib::bind(&client_impl::on_close,this,_1)); + m_client.set_fail_handler(lib::bind(&client_impl::on_fail,this,_1)); + m_client.set_message_handler(lib::bind(&client_impl::on_message,this,_1,_2)); + m_packet_mgr.set_decode_callback(lib::bind(&client_impl::on_decode,this,_1)); + m_packet_mgr.set_encode_callback(lib::bind(&client_impl::on_encode,this,_1,_2)); + template_init(); } - - client_impl::~client_impl() + + template + client_impl::~client_impl() { - this->sockets_invoke_void(&sio::socket::on_close); + this->sockets_invoke_void(socket_on_close()); sync_close(); } - - void client_impl::connect(const string& uri, const map& query, const map& headers) + + template + void client_impl::connect(const string& uri, const map& query, const map& headers) { if(m_reconn_timer) { @@ -87,8 +89,11 @@ namespace sio } } m_con_state = con_opening; - m_base_url = uri; m_reconn_made = 0; + if(!uri.empty()) + { + m_base_url = uri; + } string query_str; for(map::const_iterator it=query.begin();it!=query.end();++it){ @@ -102,12 +107,13 @@ namespace sio m_http_headers = headers; this->reset_states(); - m_client.get_io_service().dispatch(lib::bind(&client_impl::connect_impl,this,uri,m_query_string)); - m_network_thread.reset(new thread(lib::bind(&client_impl::run_loop,this)));//uri lifecycle? + m_client.get_io_service().dispatch(lib::bind(&client_impl::connect_impl,this,m_base_url,m_query_string)); + m_network_thread.reset(new thread(lib::bind(&client_impl::run_loop,this)));//uri lifecycle? } - socket::ptr const& client_impl::socket(string const& nsp) + template + socket::ptr const& client_impl::socket(string const& nsp) { lock_guard guard(m_socket_mutex); string aux; @@ -132,23 +138,25 @@ namespace sio } else { - pair p(aux,shared_ptr(new sio::socket(this,aux))); + pair p(aux,shared_ptr(new_socket(aux))); return (m_sockets.insert(p).first)->second; } } - void client_impl::close() + template + void client_impl::close() { m_con_state = con_closing; this->sockets_invoke_void(&sio::socket::close); - m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); + m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); } - void client_impl::sync_close() + template + void client_impl::sync_close() { m_con_state = con_closing; this->sockets_invoke_void(&sio::socket::close); - m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); + m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); if(m_network_thread) { m_network_thread->join(); @@ -157,12 +165,14 @@ namespace sio } /*************************protected:*************************/ - void client_impl::send(packet& p) + template + void client_impl::send(packet& p) { m_packet_mgr.encode(p); } - void client_impl::remove_socket(string const& nsp) + template + void client_impl::remove_socket(string const& nsp) { lock_guard guard(m_socket_mutex); auto it = m_sockets.find(nsp); @@ -172,23 +182,27 @@ namespace sio } } - boost::asio::io_service& client_impl::get_io_service() + template + boost::asio::io_service& client_impl::get_io_service() { return m_client.get_io_service(); } - void client_impl::on_socket_closed(string const& nsp) + template + void client_impl::on_socket_closed(string const& nsp) { if(m_socket_close_listener)m_socket_close_listener(nsp); } - void client_impl::on_socket_opened(string const& nsp) + template + void client_impl::on_socket_opened(string const& nsp) { if(m_socket_open_listener)m_socket_open_listener(nsp); } /*************************private:*************************/ - void client_impl::run_loop() + template + void client_impl::run_loop() { m_client.run(); @@ -197,16 +211,23 @@ namespace sio "run loop end"); } - void client_impl::connect_impl(const string& uri, const string& queryString) + template + void client_impl::connect_impl(const string& uri, const string& queryString) { do{ websocketpp::uri uo(uri); ostringstream ss; -#if SIO_TLS - ss<<"wss://"; -#else - ss<<"ws://"; -#endif + + if(is_tls(uri)) + { + // This requires SIO_TLS to have been compiled in. + ss<<"wss://"; + } + else + { + ss<<"ws://"; + } + const std::string host(uo.get_host()); // As per RFC2732, literal IPv6 address should be enclosed in "[" and "]". if(host.find(':')!=std::string::npos){ @@ -220,7 +241,7 @@ namespace sio } ss<<"&t="< + void client_impl::close_impl(close::status::value const& code,string const& reason) { LOG("Close by reason:"< const& payload_ptr,frame::opcode::value opcode) + template + void client_impl::send_impl(shared_ptr const& payload_ptr,frame::opcode::value opcode) { if(m_con_state == con_opened) { @@ -269,7 +292,7 @@ namespace sio if(m_ping_timer) { m_ping_timer->expires_from_now(milliseconds(m_ping_interval),timeout_ec); - m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); + m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); } lib::error_code ec; m_client.send(m_con,*payload_ptr,opcode,ec); @@ -280,7 +303,8 @@ namespace sio } } - void client_impl::ping(const boost::system::error_code& ec) + template + void client_impl::ping(const boost::system::error_code& ec) { if(ec || m_con.expired()) { @@ -299,28 +323,30 @@ namespace sio { boost::system::error_code e_code; m_ping_timer->expires_from_now(milliseconds(m_ping_interval), e_code); - m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); + m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); } if(!m_ping_timeout_timer) { m_ping_timeout_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service())); boost::system::error_code timeout_ec; m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout), timeout_ec); - m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); + m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); } } - void client_impl::timeout_pong(const boost::system::error_code &ec) + template + void client_impl::timeout_pong(const boost::system::error_code &ec) { if(ec) { return; } LOG("Pong timeout"<::close_impl, this,close::status::policy_violation,"Pong timeout")); } - void client_impl::timeout_reconnect(boost::system::error_code const& ec) + template + void client_impl::timeout_reconnect(boost::system::error_code const& ec) { if(ec) { @@ -333,18 +359,20 @@ namespace sio this->reset_states(); LOG("Reconnecting..."<::connect_impl,this,m_base_url,m_query_string)); } } - unsigned client_impl::next_delay() const + template + unsigned client_impl::next_delay() const { //no jitter, fixed power root. unsigned reconn_made = min(m_reconn_made,32);//protect the pow result to be too big. return static_cast(min(m_reconn_delay * pow(1.5,reconn_made),m_reconn_delay_max)); } - socket::ptr client_impl::get_socket_locked(string const& nsp) + template + socket::ptr client_impl::get_socket_locked(string const& nsp) { lock_guard guard(m_socket_mutex); auto it = m_sockets.find(nsp); @@ -358,7 +386,8 @@ namespace sio } } - void client_impl::sockets_invoke_void(void (sio::socket::*fn)(void)) + template + void client_impl::sockets_invoke_void(void (sio::socket::*fn)(void)) { map socks; { @@ -370,11 +399,12 @@ namespace sio } } - void client_impl::on_fail(connection_hdl con) + template + void client_impl::on_fail(connection_hdl con) { m_con.reset(); m_con_state = con_closed; - this->sockets_invoke_void(&sio::socket::on_disconnect); + this->sockets_invoke_void(socket_on_disconnect()); LOG("Connection failed." << endl); if(m_reconn_madeexpires_from_now(milliseconds(delay), ec); - m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); + m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); } else { if(m_fail_listener)m_fail_listener(); } } - - void client_impl::on_open(connection_hdl con) + + template + void client_impl::on_open(connection_hdl con) { LOG("Connected." << endl); m_con_state = con_opened; m_con = con; m_reconn_made = 0; - this->sockets_invoke_void(&sio::socket::on_open); + this->sockets_invoke_void(socket_on_open()); this->socket(""); if(m_open_listener)m_open_listener(); } - - void client_impl::on_close(connection_hdl con) + + template + void client_impl::on_close(connection_hdl con) { LOG("Client Disconnected." << endl); m_con_state = con_closed; lib::error_code ec; close::status::value code = close::status::normal; - client_type::connection_ptr conn_ptr = m_client.get_con_from_hdl(con, ec); + typename client_type::connection_ptr conn_ptr = m_client.get_con_from_hdl(con, ec); if (ec) { LOG("OnClose get conn failed"<sockets_invoke_void(&sio::socket::on_disconnect); + this->sockets_invoke_void(socket_on_disconnect()); reason = client::close_reason_normal; } else { - this->sockets_invoke_void(&sio::socket::on_disconnect); + this->sockets_invoke_void(socket_on_disconnect()); if(m_reconn_madeexpires_from_now(milliseconds(delay), ec); - m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); + m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); return; } reason = client::close_reason_drop; @@ -448,19 +480,21 @@ namespace sio m_close_listener(reason); } } - - void client_impl::on_message(connection_hdl con, client_type::message_ptr msg) + + template + void client_impl::on_message(connection_hdl con, message_ptr msg) { if (m_ping_timeout_timer) { boost::system::error_code ec; m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout),ec); - m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); + m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); } // Parse the incoming message according to socket.IO rules m_packet_mgr.put_payload(msg->get_payload()); } - - void client_impl::on_handshake(message::ptr const& message) + + template + void client_impl::on_handshake(message::ptr const& message) { if(message && message->get_flag() == message::flag_object) { @@ -496,16 +530,17 @@ namespace sio boost::system::error_code ec; m_ping_timer->expires_from_now(milliseconds(m_ping_interval), ec); if(ec)LOG("ec:"<async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); + m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); LOG("On handshake,sid:"<::close_impl, this,close::status::policy_violation,"Handshake error")); } - void client_impl::on_pong() + template + void client_impl::on_pong() { if(m_ping_timeout_timer) { @@ -514,14 +549,15 @@ namespace sio } } - void client_impl::on_decode(packet const& p) + template + void client_impl::on_decode(packet const& p) { switch(p.get_frame()) { case packet::frame_message: { socket::ptr so_ptr = get_socket_locked(p.get_nsp()); - if(so_ptr)so_ptr->on_message_packet(p); + if(so_ptr)socket_on_message_packet(so_ptr, p); break; } case packet::frame_open: @@ -539,14 +575,16 @@ namespace sio break; } } - - void client_impl::on_encode(bool isBinary,shared_ptr const& payload) + + template + void client_impl::on_encode(bool isBinary,shared_ptr const& payload) { LOG("encoded payload length:"<length()<::send_impl,this,payload,isBinary?frame::opcode::binary:frame::opcode::text)); } - - void client_impl::clear_timers() + + template + void client_impl::clear_timers() { LOG("clear timers"< + void client_impl::reset_states() { m_client.reset(); m_sid.clear(); m_packet_mgr.reset(); } + template<> + void client_impl::template_init() + { + } + #if SIO_TLS - client_impl::context_ptr client_impl::on_tls_init(connection_hdl conn) + typedef websocketpp::lib::shared_ptr context_ptr; + static context_ptr on_tls_init(connection_hdl conn) { context_ptr ctx = context_ptr(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1)); boost::system::error_code ec; @@ -584,5 +629,43 @@ namespace sio return ctx; } + + template<> + void client_impl::template_init() + { + m_client.set_tls_init_handler(&on_tls_init); + } +#endif + + bool client_impl_base::is_tls(const string& uri) + { + websocketpp::uri uo(uri); + if(boost::iequals(uo.get_scheme(), "http") || boost::iequals(uo.get_scheme(), "ws")) + { + return false; + } +#if SIO_TLS + else if(boost::iequals(uo.get_scheme(), "https") || boost::iequals(uo.get_scheme(), "wss")) + { + return true; + } +#endif + else + { + throw std::runtime_error("unsupported URI scheme"); + } + } + + socket* + client_impl_base::new_socket(const string& nsp) + { return new sio::socket(this, nsp); } + + void + client_impl_base::socket_on_message_packet(socket::ptr& s, const packet& p) + { s->on_message_packet(p); } + + template class client_impl; +#if SIO_TLS + template class client_impl; #endif } diff --git a/src/internal/sio_client_impl.h b/src/internal/sio_client_impl.h index 87ac1d03..9f197a82 100644 --- a/src/internal/sio_client_impl.h +++ b/src/internal/sio_client_impl.h @@ -16,19 +16,17 @@ #if _DEBUG || DEBUG #if SIO_TLS #include -typedef websocketpp::config::debug_asio_tls client_config; -#else +typedef websocketpp::config::debug_asio_tls client_config_tls; +#endif //SIO_TLS #include typedef websocketpp::config::debug_asio client_config; -#endif //SIO_TLS #else #if SIO_TLS #include -typedef websocketpp::config::asio_tls_client client_config; -#else +typedef websocketpp::config::asio_tls_client client_config_tls; +#endif //SIO_TLS #include typedef websocketpp::config::asio_client client_config; -#endif //SIO_TLS #endif //DEBUG #include @@ -42,11 +40,12 @@ namespace sio { using namespace websocketpp; - typedef websocketpp::client client_type; - - class client_impl { - - protected: + typedef websocketpp::client client_type_no_tls; +#if SIO_TLS + typedef websocketpp::client client_type_tls; +#endif + + struct client_impl_base { enum con_state { con_opening, @@ -54,9 +53,61 @@ namespace sio con_closing, con_closed }; - - client_impl(); - + + client_impl_base() {} + virtual ~client_impl_base() {} + + // listeners and event bindings. (see SYNTHESIS_SETTER below) + virtual void set_open_listener(client::con_listener const&)=0; + virtual void set_fail_listener(client::con_listener const&)=0; + virtual void set_reconnect_listener(client::reconnect_listener const&)=0; + virtual void set_reconnecting_listener(client::con_listener const&)=0; + virtual void set_close_listener(client::close_listener const&)=0; + virtual void set_socket_open_listener(client::socket_listener const&)=0; + virtual void set_socket_close_listener(client::socket_listener const&)=0; + + // used by sio::client + virtual void clear_con_listeners()=0; + virtual void clear_socket_listeners()=0; + virtual void connect(const std::string& uri, const std::map& queryString, + const std::map& httpExtraHeaders)=0; + virtual sio::socket::ptr const& socket(const std::string& nsp)=0; + virtual void close()=0; + virtual void sync_close()=0; + virtual bool opened() const=0; + virtual std::string const& get_sessionid() const=0; + virtual void set_reconnect_attempts(unsigned attempts)=0; + virtual void set_reconnect_delay(unsigned millis)=0; + virtual void set_reconnect_delay_max(unsigned millis)=0; + + // used by sio::socket + virtual void send(packet& p)=0; + virtual void remove_socket(std::string const& nsp)=0; + virtual boost::asio::io_service& get_io_service()=0; + virtual void on_socket_closed(std::string const& nsp)=0; + virtual void on_socket_opened(std::string const& nsp)=0; + + // used for selecting whether or not to use TLS + static bool is_tls(const std::string& uri); + + protected: + // Wrap protected member functions of sio::socket because only client_impl_base is friended. + sio::socket* new_socket(std::string const&); + void socket_on_message_packet(sio::socket::ptr&, packet const&); + typedef void (sio::socket::*socket_void_fn)(void); + inline socket_void_fn socket_on_close() { return &sio::socket::on_close; } + inline socket_void_fn socket_on_disconnect() { return &sio::socket::on_disconnect; } + inline socket_void_fn socket_on_open() { return &sio::socket::on_open; } + }; + + template + class client_impl: public client_impl_base { + public: + typedef typename client_type::message_ptr message_ptr; + + client_impl(const std::string& uri = std::string()); + void template_init(); // template-specific initialization + ~client_impl(); //set listeners and event bindings. @@ -117,7 +168,7 @@ namespace sio void set_reconnect_delay_max(unsigned millis) {m_reconn_delay_max = millis;if(m_reconn_delay>millis) m_reconn_delay = millis;} - protected: + public: void send(packet& p); void remove_socket(std::string const& nsp); @@ -159,7 +210,7 @@ namespace sio void on_close(connection_hdl con); - void on_message(connection_hdl con, client_type::message_ptr msg); + void on_message(connection_hdl con, message_ptr msg); //socketio callbacks void on_handshake(message::ptr const& message); @@ -170,12 +221,6 @@ namespace sio void clear_timers(); - #if SIO_TLS - typedef websocketpp::lib::shared_ptr context_ptr; - - context_ptr on_tls_init(connection_hdl con); - #endif - // Connection pointer for client functions. connection_hdl m_con; client_type m_client; diff --git a/src/sio_client.cpp b/src/sio_client.cpp index 48d0ce20..6922f559 100644 --- a/src/sio_client.cpp +++ b/src/sio_client.cpp @@ -14,10 +14,24 @@ using std::stringstream; namespace sio { client::client(): - m_impl(new client_impl()) + m_impl(new client_impl()) { } - + + client::client(const std::string& uri) + { + if(!client_impl_base::is_tls(uri)) + { + m_impl = new client_impl(uri); + } +#if SIO_TLS + else + { + m_impl = new client_impl(uri); + } +#endif + } + client::~client() { delete m_impl; @@ -68,6 +82,11 @@ namespace sio m_impl->clear_socket_listeners(); } + void client::connect() + { + m_impl->connect(std::string(), {}, {}); + } + void client::connect(const std::string& uri) { m_impl->connect(uri, {}, {}); diff --git a/src/sio_client.h b/src/sio_client.h index adb84e77..043f535f 100644 --- a/src/sio_client.h +++ b/src/sio_client.h @@ -13,7 +13,7 @@ namespace sio { - class client_impl; + class client_impl_base; class client { public: @@ -30,8 +30,19 @@ namespace sio typedef std::function reconnect_listener; typedef std::function socket_listener; - + + // The default constructor builds a TLS-only or a non-TLS client depending + // on which library you link with. client(); + + // This version of the constructor takes a given connection URI and selects + // TLS or non-TLS as needed. If building the library without SIO_TLS support, + // you may only use http:// or ws:// schemes, or an exception is thrown. + // When using this constructor, you may later call connect() without passing + // the URI again. If you pass another URI later to connect() it must have the + // same scheme as the one given here, or an exception will be raised. + client(const std::string& uri); + ~client(); //set listeners and event bindings. @@ -54,6 +65,8 @@ namespace sio void clear_socket_listeners(); // Client Functions - such as send, etc. + void connect(); + void connect(const std::string& uri); void connect(const std::string& uri, const std::map& query); @@ -83,7 +96,7 @@ namespace sio client(client const& cl){} void operator=(client const& cl){} - client_impl* m_impl; + client_impl_base* m_impl; }; } diff --git a/src/sio_socket.cpp b/src/sio_socket.cpp index b48134e9..59696fb5 100644 --- a/src/sio_socket.cpp +++ b/src/sio_socket.cpp @@ -106,7 +106,7 @@ namespace sio { public: - impl(client_impl *,std::string const&); + impl(client_impl_base *,std::string const&); ~impl(); void on(std::string const& event_name,event_listener_aux const& func); @@ -167,7 +167,7 @@ namespace sio static unsigned int s_global_event_id; - sio::client_impl *m_client; + sio::client_impl_base *m_client; bool m_connected; std::string m_nsp; @@ -226,7 +226,7 @@ namespace sio m_error_listener = nullptr; } - socket::impl::impl(client_impl *client,std::string const& nsp): + socket::impl::impl(client_impl_base* client, std::string const& nsp): m_client(client), m_nsp(nsp), m_connected(false) @@ -327,7 +327,7 @@ namespace sio void socket::impl::on_close() { NULL_GUARD(m_client); - sio::client_impl *client = m_client; + sio::client_impl_base *client = m_client; m_client = NULL; if(m_connection_timer) @@ -525,7 +525,7 @@ namespace sio return socket::event_listener(); } - socket::socket(client_impl* client,std::string const& nsp): + socket::socket(client_impl_base* client,std::string const& nsp): m_impl(new impl(client,nsp)) { } diff --git a/src/sio_socket.h b/src/sio_socket.h index 53fa95a8..4fd54c07 100644 --- a/src/sio_socket.h +++ b/src/sio_socket.h @@ -39,7 +39,7 @@ namespace sio friend class event_adapter; }; - class client_impl; + class client_impl_base; class packet; //The name 'socket' is taken from concept of official socket.io. @@ -75,7 +75,7 @@ namespace sio std::string const& get_namespace() const; protected: - socket(client_impl*,std::string const&); + socket(client_impl_base*,std::string const&); void on_connected(); @@ -87,7 +87,7 @@ namespace sio void on_message_packet(packet const& p); - friend class client_impl; + friend class client_impl_base; private: //disable copy constructor and assign operator.