summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Powell <petpow@saberuk.com>2019-07-21 13:44:32 +0100
committerPeter Powell <petpow@saberuk.com>2019-07-21 13:50:01 +0100
commit850b7a3ace862101a944a9332d72b6bd597c17cc (patch)
treea5b5e204de40f29942795cdffaec18037ccf16f1
parente2fcf7b3b15f86fec250b7b784bdf3d0631048c6 (diff)
Allow modules to prevent a failed connection from being closed.
-rw-r--r--include/modules.h10
-rw-r--r--src/modules.cpp1
-rw-r--r--src/usermanager.cpp10
-rw-r--r--src/users.cpp7
4 files changed, 25 insertions, 3 deletions
diff --git a/include/modules.h b/include/modules.h
index 81664d364..f5af969de 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -223,7 +223,7 @@ enum Implementation
I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnLoadModule,
I_OnUnloadModule, I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnCheckInvite,
I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckChannelBan, I_OnExtBanCheck,
- I_OnPreChangeHost, I_OnPreTopicChange,
+ I_OnPreChangeHost, I_OnPreTopicChange, I_OnConnectionFail,
I_OnPostTopicChange, I_OnPostConnect, I_OnPostDeoper,
I_OnPreChangeRealName, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete,
I_OnPostOper, I_OnPostCommand, I_OnPostJoin,
@@ -942,6 +942,14 @@ class CoreExport Module : public classbase, public usecountbase
* deny the message from being sent, or MOD_RES_PASSTHRU to let another module handle the event.
*/
virtual ModResult OnUserWrite(LocalUser* user, ClientProtocol::Message& msg);
+
+ /** Called when a user connection has been unexpectedly disconnected.
+ * @param user The user who has been unexpectedly disconnected.
+ * @param error The type of error which caused this connection failure.
+ * @return MOD_RES_ALLOW to explicitly retain the user as a zombie, MOD_RES_DENY to explicitly
+ * disconnect the user, or MOD_RES_PASSTHRU to let another module handle the event.
+ */
+ virtual ModResult OnConnectionFail(LocalUser* user, BufferedSocketError error);
};
/** ModuleManager takes care of all things module-related
diff --git a/src/modules.cpp b/src/modules.cpp
index 3e268dae6..6f7ca2694 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -140,6 +140,7 @@ void Module::OnSetUserIP(LocalUser*) { DetachEvent(I_OnSetUserIP); }
void Module::OnServiceAdd(ServiceProvider&) { DetachEvent(I_OnServiceAdd); }
void Module::OnServiceDel(ServiceProvider&) { DetachEvent(I_OnServiceDel); }
ModResult Module::OnUserWrite(LocalUser*, ClientProtocol::Message&) { DetachEvent(I_OnUserWrite); return MOD_RES_PASSTHRU; }
+ModResult Module::OnConnectionFail(LocalUser*, BufferedSocketError) { DetachEvent(I_OnConnectionFail); return MOD_RES_PASSTHRU; }
ServiceProvider::ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type)
: creator(Creator), name(Name), service(Type)
diff --git a/src/usermanager.cpp b/src/usermanager.cpp
index 6acd25ac5..4f65994aa 100644
--- a/src/usermanager.cpp
+++ b/src/usermanager.cpp
@@ -58,6 +58,16 @@ namespace
// This user didn't answer the last ping, remove them.
if (!user->lastping)
{
+ ModResult res;
+ FIRST_MOD_RESULT(OnConnectionFail, res, (user, I_ERR_TIMEOUT));
+ if (res == MOD_RES_ALLOW)
+ {
+ // A module is preventing this user from being timed out.
+ user->lastping = 1;
+ user->nextping = ServerInstance->Time() + user->MyClass->GetPingTime();
+ return;
+ }
+
time_t secs = ServerInstance->Time() - (user->nextping - user->MyClass->GetPingTime());
const std::string message = "Ping timeout: " + ConvToStr(secs) + (secs != 1 ? " seconds" : " second");
ServerInstance->Users.QuitUser(user, message);
diff --git a/src/users.cpp b/src/users.cpp
index a3807bd75..c0dc69ff4 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -308,9 +308,12 @@ bool UserIOHandler::OnSetEndPoint(const irc::sockets::sockaddrs& server, const i
return !user->quitting;
}
-void UserIOHandler::OnError(BufferedSocketError)
+void UserIOHandler::OnError(BufferedSocketError error)
{
- ServerInstance->Users->QuitUser(user, getError());
+ ModResult res;
+ FIRST_MOD_RESULT(OnConnectionFail, res, (user, error));
+ if (res != MOD_RES_ALLOW)
+ ServerInstance->Users->QuitUser(user, getError());
}
CullResult User::cull()