/* * * (C) 2003-2013 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. * * Based on the original code of Epona by Lara. * Based on the original code of Services by Andy Church. * */ #include "uplink.h" #include "logger.h" #include "config.h" #include "protocol.h" #include "servers.h" UplinkSocket *UplinkSock = NULL; class ReconnectTimer : public Timer { public: ReconnectTimer(int wait) : Timer(wait) { } void Tick(time_t) { try { Uplink::Connect(); } catch (const SocketException &ex) { Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << "): " << ex.GetReason(); } } }; void Uplink::Connect() { if (static_cast(++Anope::CurrentUplink) >= Config->Uplinks.size()) Anope::CurrentUplink = 0; ServerConfig::Uplink *u = Config->Uplinks[Anope::CurrentUplink]; new UplinkSocket(); if (!Config->LocalHost.empty()) UplinkSock->Bind(Config->LocalHost); FOREACH_MOD(I_OnPreServerConnect, OnPreServerConnect()); Anope::string ip = Anope::Resolve(u->host, u->ipv6 ? AF_INET6 : AF_INET); Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u->host << " (" << ip << "), port " << u->port; UplinkSock->Connect(ip, u->port); } UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink]->ipv6), ConnectionSocket(), BufferedSocket() { UplinkSock = this; } UplinkSocket::~UplinkSocket() { if (IRCD && Servers::GetUplink() && Servers::GetUplink()->IsSynced()) { FOREACH_MOD(I_OnServerDisconnect, OnServerDisconnect()); for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) { User *u = it->second; if (u->server == Me) { /* Don't use quitmsg here, it may contain information you don't want people to see */ IRCD->SendQuit(u, "Shutting down"); BotInfo* bi = BotInfo::Find(u->nick); if (bi != NULL) bi->introduced = false; } } IRCD->SendSquit(Me, Anope::QuitReason); this->ProcessWrite(); // Write out the last bit } if (Me) for (unsigned i = Me->GetLinks().size(); i > 0; --i) if (!Me->GetLinks()[i - 1]->IsJuped()) Me->GetLinks()[i - 1]->Delete(Me->GetName() + " " + Me->GetLinks()[i - 1]->GetName()); UplinkSock = NULL; Me->Unsync(); if (Anope::AtTerm()) { if (static_cast(Anope::CurrentUplink + 1) == Config->Uplinks.size()) { Anope::QuitReason = "Unable to connect to any uplink"; Anope::Quitting = true; Anope::ReturnValue = -1; } else { new ReconnectTimer(1); } } else if (!Anope::Quitting) { int retry = Config->RetryWait; if (retry <= 0) retry = 60; Log() << "Disconnected, retrying in " << retry << " seconds"; new ReconnectTimer(retry); } } bool UplinkSocket::ProcessRead() { BufferedSocket::ProcessRead(); for (Anope::string buf; (buf = this->GetLine()).empty() == false;) { Anope::Process(buf); User::QuitUsers(); } return true; } void UplinkSocket::OnConnect() { Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port; IRCD->SendConnect(); FOREACH_MOD(I_OnServerConnect, OnServerConnect()); } void UplinkSocket::OnError(const Anope::string &error) { Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << ")" << (!error.empty() ? (": " + error) : ""); } UplinkSocket::Message::Message() : server(NULL), user(NULL) { } UplinkSocket::Message::Message(const Server *s) : server(s), user(NULL) { } UplinkSocket::Message::Message(const User *u) : server(NULL), user(u) { if (!u) server = Me; } UplinkSocket::Message::~Message() { Anope::string message_source = ""; if (this->server != NULL) { if (this->server != Me && !this->server->IsJuped()) { Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << this->server->GetName() << " who is not from me?"; return; } message_source = this->server->GetSID(); } else if (this->user != NULL) { if (this->user->server != Me && !this->user->server->IsJuped()) { Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << this->user->nick << " who is not from me?"; return; } const BotInfo *bi = BotInfo::Find(this->user->nick); if (bi != NULL && bi->introduced == false) { Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << bi->nick << " when not introduced"; return; } message_source = this->user->GetUID(); } if (!UplinkSock) { if (!message_source.empty()) Log(LOG_DEBUG) << "Attempted to send \"" << message_source << " " << this->buffer.str() << "\" with UplinkSock NULL"; else Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" with UplinkSock NULL"; return; } if (!message_source.empty()) { UplinkSock->Write(":" + message_source + " " + this->buffer.str()); Log(LOG_RAWIO) << "Sent: :" << message_source << " " << this->buffer.str(); } else { UplinkSock->Write(this->buffer.str()); Log(LOG_RAWIO) << "Sent: " << this->buffer.str(); } }