@@ -71,6 +71,10 @@ struct relayserverinternal
7171 // matter either way.
7272 udpKeepAliveMS = 30000 - (pingMS * 3 );
7373
74+ // Some buggy client versions don't close their connection on end of app, forcing the app to stay
75+ // alive. We can't force them to close, but we can disconnect them.
76+ maxInactivityMS = 10 * 60 * 1000 ;
77+
7478 channellistingenabled = true ;
7579 }
7680 ~relayserverinternal ()
@@ -115,10 +119,12 @@ struct relayserverinternal
115119 bool channellistingenabled;
116120 long pingMS;
117121 long udpKeepAliveMS;
122+ long maxInactivityMS;
118123
119124 void pingtimertick ()
120125 {
121126 std::vector<std::shared_ptr<relayserver::client>> todisconnect;
127+ std::vector<std::shared_ptr<relayserver::client>> inactiveDisconnects;
122128
123129 framebuilder builderPingTCP (false ), builderPingUDP (true );
124130 builderPingTCP.addheader (11 , 0 ); /* ping */
@@ -133,6 +139,7 @@ struct relayserverinternal
133139
134140 long long msElapsedTCP = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - client->lasttcpmessagetime ).count ();
135141 long long msElapsedUDP = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - client->lastudpmessagetime ).count ();
142+ long long msElapsedNonPing = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - client->lastnonpingmessagetime ).count ();
136143
137144 // less than 5 seconds passed, skip the TCP ping
138145 if (msElapsedTCP < pingMS)
@@ -143,6 +150,11 @@ struct relayserverinternal
143150 if (msElapsedUDP < udpKeepAliveMS)
144151 continue ;
145152 }
153+ if (msElapsedNonPing > maxInactivityMS)
154+ {
155+ inactiveDisconnects.push_back (client);
156+ continue ;
157+ }
146158
147159 // pongedOnTCP is true until client hasn't sent a message within PingMS period.
148160 // Then it's set to false and a ping message sent, which happens AFTER this if().
@@ -170,10 +182,11 @@ struct relayserverinternal
170182
171183 builderPingTCP.framereset ();
172184
173- if (todisconnect.empty ())
185+ if (todisconnect.empty () && inactiveDisconnects. empty () )
174186 return ;
175187
176188 serverReadLock.lw_unlock ();
189+
177190 for (auto & client : todisconnect)
178191 {
179192 if (client->_readonly )
@@ -212,6 +225,35 @@ struct relayserverinternal
212225 client->socket ->close (lw_true);
213226 }
214227 }
228+
229+ for (auto & client : inactiveDisconnects)
230+ {
231+ if (client->_readonly )
232+ continue ;
233+
234+ if (!serverReadLock.isEnabled ())
235+ serverReadLock.lw_relock ();
236+ if (std::find (clients.begin (), clients.end (), client) != clients.end ())
237+ {
238+ serverReadLock.lw_unlock ();
239+ // auto clientWriteLock = clientsocket->lock.createWriteLock();
240+ if (client->_readonly )
241+ continue ;
242+
243+ std::string impl = client->clientImplStr ;
244+ if (!impl.empty () && impl.back () == ' .' )
245+ impl.erase (impl.cend ());
246+
247+ auto error = lacewing::error_new ();
248+ error->add (" Disconnecting client ID %i due to 10 min inactivity timeout; client impl \" %s\" ." , client->_id , impl.c_str ());
249+ handlererror (this ->server , error);
250+ lacewing::error_delete (error);
251+
252+ client->send (0 , " You're being kicked for 10 minutes of inactivity." , 0 );
253+ // Close nicely
254+ client->socket ->close (lw_false);
255+ }
256+ }
215257 }
216258
217259 // for debug
@@ -1327,6 +1369,9 @@ bool relayserverinternal::client_messagehandler(std::shared_ptr<relayserver::cli
13271369 else
13281370 client->lasttcpmessagetime = ::std::chrono::steady_clock::now ();
13291371
1372+ if (messagetypeid != 9 )
1373+ client->lastnonpingmessagetime = ::std::chrono::steady_clock::now ();
1374+
13301375 std::stringstream errStr;
13311376 bool trustedClient = true ;
13321377
@@ -1865,13 +1910,6 @@ bool relayserverinternal::client_messagehandler(std::shared_ptr<relayserver::cli
18651910 // auto cliWriteLock = cliReadLock.lw_upgrade();
18661911 client->_readonly = true ;
18671912
1868- // RAOK DEBUG INFO
1869- #ifdef _DEBUG
1870- std::stringstream err;
1871- err << " client_messagehandler: Emergency drop line " << __LINE__ << " . Client ID " << client->_id << " , name " << client->name () << " has been marked as readonly." ;
1872- makestrstrerror (err);
1873- #endif
1874-
18751913 cliReadLock.lw_unlock ();
18761914 auto cliWriteLock = client->lock .createWriteLock ();
18771915
@@ -1996,7 +2034,7 @@ relayserver::client::client(relayserverinternal &internal, lacewing::server_clie
19962034
19972035 // connectTime not started until handshake is done
19982036 // last message can be considered the connect time
1999- lasttcpmessagetime = ::std::chrono::steady_clock::now ();
2037+ lastnonpingmessagetime = lasttcpmessagetime = ::std::chrono::steady_clock::now ();
20002038 lastudpmessagetime = ::std::chrono::steady_clock::time_point::time_point ();
20012039}
20022040
@@ -2117,13 +2155,6 @@ void relayserver::client::disconnect()
21172155{
21182156 _readonly = true ;
21192157
2120- // RAOK DEBUG INFO
2121- #ifdef _DEBUG
2122- std::stringstream err;
2123- err << " relayserver::client::disconnect: Emergency drop line " << __LINE__ << " . Client ID " << _id << " , name " << name () << " has been marked as readonly." ;
2124- server.makestrstrerror (err);
2125- #endif
2126-
21272158 lacewing::writelock wl = lock.createWriteLock ();
21282159 if (socket && socket->valid ())
21292160 socket->close ();
0 commit comments