summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/inspircd.conf.example19
-rw-r--r--src/modules/m_spanningtree.cpp163
2 files changed, 116 insertions, 66 deletions
diff --git a/docs/inspircd.conf.example b/docs/inspircd.conf.example
index 2c31849e1..ca06d0dc9 100644
--- a/docs/inspircd.conf.example
+++ b/docs/inspircd.conf.example
@@ -399,6 +399,24 @@
# into this value. If it is not defined, then only #
# the ipaddr field of the server shall be allowed. #
# #
+# failover - If you define this option, it must be the name of a #
+# different link tag in your configuration. This #
+# option causes the ircd to attempt a connection to #
+# the failover link in the event that the connection #
+# to this server fails. For example, you could define #
+# two hub uplinks to a leaf server, and set an #
+# american server to autoconnect, with a european #
+# hub as its failover. In this situation, your ircd #
+# will only try the link to the european hub if the #
+# american hub is unreachable. NOTE that for the #
+# intents and purposes of this option, an unreachable #
+# server is one which DOES NOT ANSWER THE CONNECTION. #
+# If the server answers the connection with accept(), #
+# EVEN IF THE CREDENTIALS ARE INVALID, the failover #
+# link will not be tried! Failover settings will also #
+# apply to autoconnected servers as well as manually #
+# connected ones. #
+# #
# to u:line a server (give it extra privilages required for running #
# services, Q, etc) you must include the <uline server> tag as shown #
# in the example below. You can have as many of these as you like. #
@@ -430,6 +448,7 @@
port="7000"
allowmask="69.58.44.0/24"
autoconnect="300"
+ failover="hub.other.net"
sendpass="outgoing!password"
recvpass="incoming!password">
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index 4f25b01d3..395644772 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -491,17 +491,21 @@ class TreeServer : public classbase
class Link : public classbase
{
public:
- irc::string Name;
- std::string IPAddr;
- int Port;
- std::string SendPass;
- std::string RecvPass;
- unsigned long AutoConnect;
- time_t NextConnectTime;
- std::string EncryptionKey;
- bool HiddenFromStats;
+ irc::string Name;
+ std::string IPAddr;
+ int Port;
+ std::string SendPass;
+ std::string RecvPass;
+ unsigned long AutoConnect;
+ time_t NextConnectTime;
+ std::string EncryptionKey;
+ bool HiddenFromStats;
+ irc::string FailOver;
};
+void DoFailOver(Link* x);
+Link* FindLink(const std::string& name);
+
/* The usual stuff for inspircd modules,
* plus the vector of Link classes which we
* use to store the <link> tags from the config
@@ -754,7 +758,10 @@ class TreeSocket : public InspSocket
*/
if (e == I_ERR_CONNECT)
{
- this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection refused");
+ this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused");
+ Link* MyLink = FindLink(myhost);
+ if (MyLink)
+ DoFailOver(MyLink);
}
}
@@ -3222,6 +3229,9 @@ class TreeSocket : public InspSocket
if (this->LinkState == CONNECTING)
{
this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out.");
+ Link* MyLink = FindLink(myhost);
+ if (MyLink)
+ DoFailOver(MyLink);
}
}
@@ -3310,6 +3320,7 @@ class ServernameResolver : public Resolver
/* Something barfed, show the opers */
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno));
delete newsocket;
+ DoFailOver(&MyLink);
}
}
}
@@ -3318,6 +3329,7 @@ class ServernameResolver : public Resolver
{
/* Ooops! */
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str());
+ DoFailOver(&MyLink);
}
};
@@ -3571,6 +3583,7 @@ void ReadConfiguration(bool rebind)
std::string Allow = Conf->ReadValue("link","allowmask",j);
L.Name = (Conf->ReadValue("link","name",j)).c_str();
L.IPAddr = Conf->ReadValue("link","ipaddr",j);
+ L.FailOver = Conf->ReadValue("link","failover",j).c_str();
L.Port = Conf->ReadInteger("link","port",j,true);
L.SendPass = Conf->ReadValue("link","sendpass",j);
L.RecvPass = Conf->ReadValue("link","recvpass",j);
@@ -4033,6 +4046,69 @@ class ModuleSpanningTree : public Module
}
}
+ void ConnectServer(Link* x)
+ {
+ insp_inaddr binip;
+
+ /* Do we already have an IP? If so, no need to resolve it. */
+ if (insp_aton(x->IPAddr.c_str(), &binip) > 0)
+ {
+ TreeSocket* newsocket = new TreeSocket(ServerInstance, x->IPAddr,x->Port,false,10,x->Name.c_str());
+ if (newsocket->GetFd() > -1)
+ {
+ /* Handled automatically on success */
+ }
+ else
+ {
+ ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));
+ delete newsocket;
+ this->DoFailOver(x);
+ }
+ }
+ else
+ {
+ try
+ {
+ ServernameResolver* snr = new ServernameResolver(ServerInstance,x->IPAddr, *x);
+ ServerInstance->AddResolver(snr);
+ }
+ catch (ModuleException& e)
+ {
+ ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
+ this->DoFailOver(x);
+ }
+ }
+ }
+
+ void DoFailOver(Link* x)
+ {
+ if (x->FailOver.length())
+ {
+ Link* TryThisOne = this->FindLink(x->FailOver.c_str());
+ if (TryThisOne)
+ {
+ ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str());
+ ConnectServer(TryThisOne);
+ }
+ else
+ {
+ ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str());
+ }
+ }
+ }
+
+ Link* FindLink(const std::string& name)
+ {
+ for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++)
+ {
+ if (ServerInstance->MatchText(x->Name.c_str(), name.c_str()))
+ {
+ return &(*x);
+ }
+ }
+ return NULL;
+ }
+
void AutoConnectServers(time_t curtime)
{
for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++)
@@ -4046,35 +4122,7 @@ class ModuleSpanningTree : public Module
{
// an autoconnected server is not connected. Check if its time to connect it
ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect);
-
- insp_inaddr binip;
-
- /* Do we already have an IP? If so, no need to resolve it. */
- if (insp_aton(x->IPAddr.c_str(), &binip) > 0)
- {
- TreeSocket* newsocket = new TreeSocket(ServerInstance, x->IPAddr,x->Port,false,10,x->Name.c_str());
- if (newsocket->GetFd() > -1)
- {
- }
- else
- {
- ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Error autoconnecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));
- delete newsocket;
- }
- }
- else
- {
- try
- {
- ServernameResolver* snr = new ServernameResolver(ServerInstance,x->IPAddr, *x);
- ServerInstance->AddResolver(snr);
- }
- catch (ModuleException& e)
- {
- ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
- }
- }
-
+ this->ConnectServer(&(*x));
}
}
}
@@ -4127,33 +4175,7 @@ class ModuleSpanningTree : public Module
if (!CheckDupe)
{
user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()),x->Port);
- insp_inaddr binip;
-
- /* Do we already have an IP? If so, no need to resolve it. */
- if (insp_aton(x->IPAddr.c_str(), &binip) > 0)
- {
- TreeSocket* newsocket = new TreeSocket(ServerInstance,x->IPAddr,x->Port,false,10,x->Name.c_str());
- if (newsocket->GetFd() > -1)
- {
- }
- else
- {
- ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));
- delete newsocket;
- }
- }
- else
- {
- try
- {
- ServernameResolver* snr = new ServernameResolver(ServerInstance, x->IPAddr, *x);
- ServerInstance->AddResolver(snr);
- }
- catch (ModuleException& e)
- {
- ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
- }
- }
+ ConnectServer(&(*x));
return 1;
}
else
@@ -4801,6 +4823,15 @@ class ModuleSpanningTree : public Module
}
};
+void DoFailOver(Link* x)
+{
+ TreeProtocolModule->DoFailOver(x);
+}
+
+Link* FindLink(const std::string& name)
+{
+ return TreeProtocolModule->FindLink(name);
+}
class ModuleSpanningTreeFactory : public ModuleFactory
{