1010#include < sstream>
1111#include < boost/date_time/posix_time/posix_time.hpp>
1212#include < mutex>
13+ #include < cmath>
1314// Comment this out to disable handshake logging to stdout
1415#if DEBUG || _DEBUG
1516#define LOG (x ) std::cout << x
@@ -27,6 +28,7 @@ namespace sio
2728 m_ping_timeout (0 ),
2829 m_network_thread (),
2930 m_reconn_attempts (0xFFFFFFFF ),
31+ m_reconn_made (0 ),
3032 m_reconn_delay (5000 ),
3133 m_reconn_delay_max (25000 )
3234 {
@@ -57,25 +59,6 @@ namespace sio
5759 sync_close ();
5860 }
5961
60- // Websocket++ client client
61- void client_impl::on_fail (connection_hdl con)
62- {
63- m_con.reset ();
64- m_con_state = con_closed;
65- this ->sockets_invoke_void (&sio::socket::on_disconnect);
66- LOG (" Connection failed." << std::endl);
67- if (m_fail_listener)m_fail_listener ();
68- }
69-
70- void client_impl::on_pong ()
71- {
72- if (m_ping_timeout_timer)
73- {
74- m_ping_timeout_timer->cancel ();
75- m_ping_timeout_timer.reset ();
76- }
77- }
78-
7962 void client_impl::on_handshake (message::ptr const & message)
8063 {
8164 if (message && message->get_flag () == message::flag_object)
@@ -113,19 +96,43 @@ namespace sio
11396 m_ping_timer->expires_from_now (milliseconds (m_ping_interval), ec);
11497 if (ec)LOG (" ec:" <<ec.message ()<<std::endl);
11598 m_ping_timer->async_wait (lib::bind (&client_impl::__ping,this ,lib::placeholders::_1));
116- LOG (" On handshake,sid:" <<m_sid<<" ,ping interval:" <<m_ping_interval<<" ,ping timeout" <<" m_ping_timeout " << m_ping_timeout<<std::endl);
99+ LOG (" On handshake,sid:" <<m_sid<<" ,ping interval:" <<m_ping_interval<<" ,ping timeout" <<m_ping_timeout<<std::endl);
117100 return ;
118101 }
119102 failed:
120103 // just close it.
121104 m_client.get_io_service ().dispatch (lib::bind (&client_impl::__close, this ,close::status::policy_violation," Handshake error" ));
122105 }
106+
107+ // Websocket++ client client
108+ void client_impl::on_fail (connection_hdl con)
109+ {
110+ m_con.reset ();
111+ m_con_state = con_closed;
112+ this ->sockets_invoke_void (&sio::socket::on_disconnect);
113+ LOG (" Connection failed." << std::endl);
114+ if (m_reconn_made<m_reconn_attempts)
115+ {
116+ LOG (" Reconnect for attempt:" <<m_reconn_made<<std::endl);
117+ unsigned delay = this ->next_delay ();
118+ if (m_reconnect_listener) m_reconnect_listener (m_reconn_made,delay);
119+ m_reconn_timer.reset (new boost::asio::deadline_timer (m_client.get_io_service ()));
120+ boost::system::error_code ec;
121+ m_reconn_timer->expires_from_now (milliseconds (delay), ec);
122+ m_reconn_timer->async_wait (lib::bind (&client_impl::reconnect,this ,lib::placeholders::_1));
123+ }
124+ else
125+ {
126+ if (m_fail_listener)m_fail_listener ();
127+ }
128+ }
123129
124130 void client_impl::on_open (connection_hdl con)
125131 {
126132 LOG (" Connected." << std::endl);
127133 m_con_state = con_opened;
128134 m_con = con;
135+ m_reconn_made = 0 ;
129136 this ->sockets_invoke_void (&sio::socket::on_open);
130137 if (m_open_listener)m_open_listener ();
131138 }
@@ -156,12 +163,22 @@ namespace sio
156163 else
157164 {
158165 this ->sockets_invoke_void (&sio::socket::on_disconnect);
166+ if (m_reconn_made<m_reconn_attempts)
167+ {
168+ LOG (" Reconnect for attempt:" <<m_reconn_made<<std::endl);
169+ unsigned delay = this ->next_delay ();
170+ if (m_reconnect_listener) m_reconnect_listener (m_reconn_made,delay);
171+ m_reconn_timer.reset (new boost::asio::deadline_timer (m_client.get_io_service ()));
172+ boost::system::error_code ec;
173+ m_reconn_timer->expires_from_now (milliseconds (delay), ec);
174+ m_reconn_timer->async_wait (lib::bind (&client_impl::reconnect,this ,lib::placeholders::_1));
175+ return ;
176+ }
159177 reason = client::close_reason_drop;
160178 }
161179
162180 if (m_close_listener)
163181 {
164-
165182 m_close_listener (reason);
166183 }
167184 }
@@ -177,6 +194,15 @@ namespace sio
177194 m_packet_mgr.put_payload (msg->get_payload ());
178195 }
179196
197+ void client_impl::on_pong ()
198+ {
199+ if (m_ping_timeout_timer)
200+ {
201+ m_ping_timeout_timer->cancel ();
202+ m_ping_timeout_timer.reset ();
203+ }
204+ }
205+
180206 void client_impl::on_pong_timeout ()
181207 {
182208 LOG (" Pong timeout" <<std::endl);
@@ -257,6 +283,11 @@ namespace sio
257283 void client_impl::__close (close::status::value const & code,std::string const & reason)
258284 {
259285 LOG (" Close by reason:" <<reason << std::endl);
286+ if (m_reconn_timer)
287+ {
288+ m_reconn_timer->cancel ();
289+ m_reconn_timer.reset ();
290+ }
260291 if (m_con.expired ())
261292 {
262293 std::cerr << " Error: No active session" << std::endl;
@@ -286,6 +317,12 @@ namespace sio
286317 m_network_thread.reset ();
287318 }
288319 }
320+
321+ unsigned client_impl::next_delay () const
322+ {
323+ // no jitter, fixed power root.
324+ return (unsigned )min (m_reconn_delay * pow (1.5 ,m_reconn_made),m_reconn_delay_max);
325+ }
289326
290327 void client_impl::send (packet& p)
291328 {
@@ -392,6 +429,11 @@ namespace sio
392429
393430 void client_impl::connect (const std::string& uri)
394431 {
432+ if (m_reconn_timer)
433+ {
434+ m_reconn_timer->cancel ();
435+ m_reconn_timer.reset ();
436+ }
395437 if (m_network_thread)
396438 {
397439 if (m_con_state == con_closing||m_con_state == con_closed)
@@ -400,6 +442,7 @@ namespace sio
400442 // if client is closed, still need to join,
401443 // but in closed case,join will return immediately.
402444 m_network_thread->join ();
445+ m_network_thread.reset ();// defensive
403446 }
404447 else
405448 {
@@ -408,33 +451,30 @@ namespace sio
408451 }
409452 }
410453 m_con_state = con_opening;
454+ m_base_url = uri;
455+ m_reconn_made = 0 ;
411456 this ->reset_states ();
412457 m_client.get_io_service ().dispatch (lib::bind (&client_impl::__connect,this ,uri));
413458 m_network_thread.reset (new std::thread (lib::bind (&client_impl::run_loop,this )));// uri lifecycle?
414459
415460 }
416461
417- // void client_impl::reconnect(const std::string& uri)
418- // {
419- // if(m_network_thread)
420- // {
421- // if(m_con_state == con_closing)
422- // {
423- // m_network_thread->join();
424- // }
425- // else
426- // {
427- // return;
428- // }
429- // }
430- // if(m_con_state == con_closed)
431- // {
432- // m_con_state = con_opening;
433-
434- // m_client.get_io_service().dispatch(lib::bind(&client_impl::__connect,this,uri));
435- // m_network_thread.reset(new std::thread(lib::bind(&client_impl::run_loop,this)));//uri
436- // }
437- // }
462+ void client_impl::reconnect (boost::system::error_code const & ec)
463+ {
464+ if (ec)
465+ {
466+ return ;
467+ }
468+ if (m_con_state == con_closed)
469+ {
470+ m_con_state = con_opening;
471+ m_reconn_made++;
472+ this ->reset_states ();
473+ LOG (" Reconnecting..." <<std::endl);
474+ if (m_reconnecting_listener) m_reconnecting_listener ();
475+ m_client.get_io_service ().dispatch (lib::bind (&client_impl::__connect,this ,m_base_url));
476+ }
477+ }
438478
439479 socket::ptr const & client_impl::socket (std::string const & nsp)
440480 {
0 commit comments