anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

uplink.cpp (6021B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "uplink.h"
     13 #include "logger.h"
     14 #include "config.h"
     15 #include "protocol.h"
     16 #include "servers.h"
     17 
     18 UplinkSocket *UplinkSock = NULL;
     19 
     20 class ReconnectTimer : public Timer
     21 {
     22  public:
     23 	ReconnectTimer(int wait) : Timer(wait) { }
     24 
     25 	void Tick(time_t)
     26 	{
     27 		try
     28 		{
     29 			Uplink::Connect();
     30 		}
     31 		catch (const SocketException &ex)
     32 		{
     33 			Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason();
     34 		}
     35 	}
     36 };
     37 
     38 void Uplink::Connect()
     39 {
     40 	if (Config->Uplinks.empty())
     41 	{
     42 		Log() << "Warning: There are no configured uplinks.";
     43 		return;
     44 	}
     45 
     46 	if (static_cast<unsigned>(++Anope::CurrentUplink) >= Config->Uplinks.size())
     47 		Anope::CurrentUplink = 0;
     48 
     49 	Configuration::Uplink &u = Config->Uplinks[Anope::CurrentUplink];
     50 
     51 	new UplinkSocket();
     52 	if (!Config->GetBlock("serverinfo")->Get<const Anope::string>("localhost").empty())
     53 		UplinkSock->Bind(Config->GetBlock("serverinfo")->Get<const Anope::string>("localhost"));
     54 	FOREACH_MOD(OnPreServerConnect, ());
     55 	Anope::string ip = Anope::Resolve(u.host, u.ipv6 ? AF_INET6 : AF_INET);
     56 	Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u.host << " (" << ip << '/' << u.port << ") with protocol " << IRCD->GetProtocolName();
     57 	UplinkSock->Connect(ip, u.port);
     58 }
     59 
     60 UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink].ipv6), ConnectionSocket(), BufferedSocket()
     61 {
     62 	error = false;
     63 	UplinkSock = this;
     64 }
     65 
     66 UplinkSocket::~UplinkSocket()
     67 {
     68 	if (!error && !Anope::Quitting)
     69 	{
     70 		this->OnError("");
     71 		Module *protocol = ModuleManager::FindFirstOf(PROTOCOL);
     72 		if (protocol && !protocol->name.find("inspircd"))
     73 			Log(LOG_TERMINAL) << "Check that you have loaded m_spanningtree.so on InspIRCd, and are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)";
     74 		else
     75 			Log(LOG_TERMINAL) << "Check that you are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)";
     76 	}
     77 
     78 	if (IRCD && Servers::GetUplink() && Servers::GetUplink()->IsSynced())
     79 	{
     80 		FOREACH_MOD(OnServerDisconnect, ());
     81 
     82 		for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
     83 		{
     84 			User *u = it->second;
     85 
     86 			if (u->server == Me)
     87 			{
     88 				/* Don't use quitmsg here, it may contain information you don't want people to see */
     89 				IRCD->SendQuit(u, "Shutting down");
     90 				BotInfo* bi = BotInfo::Find(u->GetUID());
     91 				if (bi != NULL)
     92 					bi->introduced = false;
     93 			}
     94 		}
     95 
     96 		IRCD->SendSquit(Me, Anope::QuitReason);
     97 	}
     98 
     99 	for (unsigned i = Me->GetLinks().size(); i > 0; --i)
    100 		if (!Me->GetLinks()[i - 1]->IsJuped())
    101 			Me->GetLinks()[i - 1]->Delete(Me->GetName() + " " + Me->GetLinks()[i - 1]->GetName());
    102 
    103 	this->ProcessWrite(); // Write out the last bit
    104 	UplinkSock = NULL;
    105 
    106 	Me->Unsync();
    107 
    108 	if (Anope::AtTerm())
    109 	{
    110 		if (static_cast<unsigned>(Anope::CurrentUplink + 1) == Config->Uplinks.size())
    111 		{
    112 			Anope::QuitReason = "Unable to connect to any uplink";
    113 			Anope::Quitting = true;
    114 			Anope::ReturnValue = -1;
    115 		}
    116 		else
    117 		{
    118 			new ReconnectTimer(1);
    119 		}
    120 	}
    121 	else if (!Anope::Quitting)
    122 	{
    123 		time_t retry = Config->GetBlock("options")->Get<time_t>("retrywait");
    124 
    125 		Log() << "Disconnected, retrying in " << retry << " seconds";
    126 		new ReconnectTimer(retry);
    127 	}
    128 }
    129 
    130 bool UplinkSocket::ProcessRead()
    131 {
    132 	bool b = BufferedSocket::ProcessRead();
    133 	for (Anope::string buf; (buf = this->GetLine()).empty() == false;)
    134 	{
    135 		Anope::Process(buf);
    136 		User::QuitUsers();
    137 		Channel::DeleteChannels();
    138 	}
    139 	return b;
    140 }
    141 
    142 void UplinkSocket::OnConnect()
    143 {
    144 	Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port;
    145 	IRCD->SendConnect();
    146 	FOREACH_MOD(OnServerConnect, ());
    147 }
    148 
    149 void UplinkSocket::OnError(const Anope::string &err)
    150 {
    151 	Anope::string what = !this->flags[SF_CONNECTED] ? "Unable to connect to" : "Lost connection from";
    152 	Log(LOG_TERMINAL) << what << " uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << ")" << (!err.empty() ? (": " + err) : "");
    153 	error |= !err.empty();
    154 }
    155 
    156 UplinkSocket::Message::Message() : source(Me)
    157 {
    158 }
    159 
    160 UplinkSocket::Message::Message(const MessageSource &src) : source(src)
    161 {
    162 }
    163 
    164 UplinkSocket::Message::~Message()
    165 {
    166 	Anope::string message_source;
    167 
    168 	if (this->source.GetServer() != NULL)
    169 	{
    170 		const Server *s = this->source.GetServer();
    171 
    172 		if (s != Me && !s->IsJuped())
    173 		{
    174 			Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << s->GetName() << " who is not from me?";
    175 			return;
    176 		}
    177 
    178 		message_source = s->GetSID();
    179 	}
    180 	else if (this->source.GetUser() != NULL)
    181 	{
    182 		const User *u = this->source.GetUser();
    183 
    184 		if (u->server != Me && !u->server->IsJuped())
    185 		{
    186 			Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << u->nick << " who is not from me?";
    187 			return;
    188 		}
    189 
    190 		const BotInfo *bi = this->source.GetBot();
    191 		if (bi != NULL && bi->introduced == false)
    192 		{
    193 			Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << bi->nick << " when not introduced";
    194 			return;
    195 		}
    196 
    197 		message_source = u->GetUID();
    198 	}
    199 
    200 	if (!UplinkSock)
    201 	{
    202 		if (!message_source.empty())
    203 			Log(LOG_DEBUG) << "Attempted to send \"" << message_source << " " << this->buffer.str() << "\" with UplinkSock NULL";
    204 		else
    205 			Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" with UplinkSock NULL";
    206 		return;
    207 	}
    208 
    209 	Anope::string sent = IRCD->Format(message_source, this->buffer.str());
    210 	UplinkSock->Write(sent);
    211 	Log(LOG_RAWIO) << "Sent: " << sent;
    212 }