Skip to content

Commit d31405e

Browse files
committed
Add kicking due to inactivity (sending non-ping msg = activity)
Due to some buggy client implementations retaining connection beyond end of app (even keeping app running by doing so), I've added a 10 minute delay. The limit is that large due to the fact someone waiting in an empty lobby may use a lot of time with no activity legitimately. Worth noting a passive receiving client in an channel with active clients, does not itself count as active. Only sending non-ping messages qualifies.
1 parent fdedec7 commit d31405e

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

Lacewing/Lacewing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,6 +1985,7 @@ struct relayserver
19851985
::std::chrono::high_resolution_clock::time_point connectTime;
19861986
::std::chrono::steady_clock::time_point lasttcpmessagetime;
19871987
::std::chrono::steady_clock::time_point lastudpmessagetime; // UDP problem where unused connections are dropped by router, so must keep these separate
1988+
::std::chrono::steady_clock::time_point lastnonpingmessagetime; // For clients that go idle
19881989
framereader reader;
19891990
std::vector<std::shared_ptr<channel>> channels;
19901991
std::string _name, _prevname;

Lacewing/RelayServer.cc

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)