summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/example.conf25
-rw-r--r--include/anope.h7
-rw-r--r--include/config.h4
-rw-r--r--include/dns.h4
-rw-r--r--include/extern.h16
-rw-r--r--include/modules.h12
-rw-r--r--include/services.h13
-rw-r--r--include/sockets.h56
-rw-r--r--modules/core/db_mysql.cpp2
-rw-r--r--modules/core/os_restart.cpp2
-rw-r--r--modules/core/os_shutdown.cpp2
-rw-r--r--modules/extra/m_ssl.cpp152
-rw-r--r--modules/extra/m_xmlrpc.cpp37
-rw-r--r--modules/protocol/bahamut.cpp2
-rw-r--r--modules/protocol/inspircd-ts6.h2
-rw-r--r--modules/protocol/inspircd11.cpp2
-rw-r--r--modules/protocol/plexus.cpp2
-rw-r--r--modules/protocol/ratbox.cpp2
-rw-r--r--modules/protocol/unreal.cpp2
-rw-r--r--src/config.cpp3
-rw-r--r--src/dns.cpp23
-rw-r--r--src/init.cpp1
-rw-r--r--src/main.cpp444
-rw-r--r--src/messages.cpp2
-rw-r--r--src/misc.cpp9
-rw-r--r--src/modulemanager.cpp8
-rw-r--r--src/socketengines/socketengine_epoll.cpp2
-rw-r--r--src/socketengines/socketengine_poll.cpp2
-rw-r--r--src/socketengines/socketengine_select.cpp2
-rw-r--r--src/sockets.cpp132
30 files changed, 525 insertions, 447 deletions
diff --git a/data/example.conf b/data/example.conf
index f98b8b9f5..6aed17fda 100644
--- a/data/example.conf
+++ b/data/example.conf
@@ -457,14 +457,6 @@ options
botmodes = "ao"
/*
- * How many times services should attempt to reconnect to the uplink before giving up
- * Comment this out to never give up.
- *
- * This directive is optional.
- */
- maxretries = 10
-
- /*
* How long to wait between connection retries, in seconds.
*/
retrywait = 60
@@ -707,17 +699,19 @@ oper
#certfp = "ed3383b3f7d74e89433ddaa4a6e5b2d7"
}
+/*
oper
{
- #name = "nick2"
+ name = "nick2"
type = "Services Administrator"
}
oper
{
- #name = "nick3"
+ name = "nick3"
type = "Helper"
}
+*/
/*
* [OPTIONAL] Mail Config
@@ -1742,16 +1736,19 @@ defcon
* You may also include executable files, which will be executed and
* the output from it will be included into your configuration.
*/
+
+/*
include
{
- #type = "file"
- #name = "some_other.conf"
+ type = "file"
+ name = "some_other.conf"
}
include
{
- #type = "executable"
- #name = "/usr/bin/wget -q -O - http://some.miconfigured.network.com/services.conf"
+ type = "executable"
+ name = "/usr/bin/wget -q -O - http://some.miconfigured.network.com/services.conf"
}
+*/
/*
* [OPTIONAL] Non-Core Modules
diff --git a/include/anope.h b/include/anope.h
index 0e25bbb93..83f45d39b 100644
--- a/include/anope.h
+++ b/include/anope.h
@@ -368,7 +368,12 @@ namespace Anope
*/
extern CoreExport string printf(const char *fmt, ...);
- /** Return the last error, uses errno/GetLastError() to determin this
+ /** Return the last error code
+ * @return The error code
+ */
+ extern CoreExport int LastErrorCode();
+
+ /** Return the last error, uses errno/GetLastError() to determine this
* @return An error message
*/
extern CoreExport const Anope::string LastError();
diff --git a/include/config.h b/include/config.h
index b06aa60d8..07815466e 100644
--- a/include/config.h
+++ b/include/config.h
@@ -345,7 +345,7 @@ class CoreExport ServerConfig
/* Host to connect to **/
Anope::string LocalHost;
/* List of uplink servers to try and connect to */
- std::list<Uplink *> Uplinks;
+ std::vector<Uplink *> Uplinks;
/* Our server name */
Anope::string ServerName;
@@ -453,8 +453,6 @@ class CoreExport ServerConfig
Anope::string BotModes;
/* THe actual modes */
ChannelStatus BotModeList;
- /* How many times to try and reconnect to the uplink before giving up */
- unsigned MaxRetries;
/* How long to wait between connection attempts */
int RetryWait;
/* If services should hide unprivileged commands */
diff --git a/include/dns.h b/include/dns.h
index 6e79603d7..cb6d6b5c7 100644
--- a/include/dns.h
+++ b/include/dns.h
@@ -152,6 +152,10 @@ class DNSSocket : public ConnectionSocket
bool ProcessRead();
bool ProcessWrite();
+
+ void OnConnect();
+
+ void OnError(const Anope::string &error);
};
/** DNS manager, manages the connection and all requests
diff --git a/include/extern.h b/include/extern.h
index 0b319ceaf..7774c104f 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -85,7 +85,6 @@ E void introduce_user(const Anope::string &user);
E bool GetCommandLineArgument(const Anope::string &name, char shortname = 0);
E bool GetCommandLineArgument(const Anope::string &name, char shortname, Anope::string &param);
E void Init(int ac, char **av);
-E Uplink *uplink_server;
/**** ircd.c ****/
E void pmodule_ircd_proto(IRCDProto *);
@@ -114,27 +113,16 @@ E bool noexpire;
E bool protocoldebug;
E bool quitting;
-E bool shutting_down;
+E bool restarting;
E Anope::string quitmsg;
E bool save_data;
E time_t start_time;
E ConnectionSocket *UplinkSock;
+E int CurrentUplink;
E void save_databases();
E void sighandler(int signum);
-E void do_restart_services();
-
-/* The socket to our uplink */
-class CoreExport UplinkSocket : public ConnectionSocket
-{
- public:
- UplinkSocket(bool ipv6 = false);
-
- virtual ~UplinkSocket();
-
- bool Read(const Anope::string &buf);
-};
/**** messages.cpp ****/
diff --git a/include/modules.h b/include/modules.h
index d24348b48..ff0c576a0 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -481,12 +481,9 @@ class CoreExport Module : public Extensible
*/
virtual void OnChanExpire(ChannelInfo *ci) { }
- /** Called before Anope connects to its uplink
- * @param u The uplink we're going to connect to
- * @param Number What number the uplink is
- * @return Other than EVENT_CONTINUE to stop attempting to connect
+ /** Called before Anope connecs to its uplink
*/
- virtual EventReturn OnPreServerConnect(Uplink *u, int Number) { return EVENT_CONTINUE; }
+ virtual void OnPreServerConnect() { }
/** Called when Anope connects to its uplink
*/
@@ -1079,7 +1076,7 @@ enum Implementation
I_OnModuleLoad, I_OnModuleUnload,
/* Other */
- I_OnReload, I_OnPreServerConnect, I_OnNewServer, I_OnServerConnect, I_OnPreUplinkSync, I_OnServerDisconnect, I_OnPreCommandRun,
+ I_OnReload, I_OnNewServer, I_OnPreServerConnect, I_OnServerConnect, I_OnPreUplinkSync, I_OnServerDisconnect, I_OnPreCommandRun,
I_OnPreCommand, I_OnPostCommand, I_OnRestart, I_OnShutdown, I_OnSignal,
I_OnServerQuit, I_OnTopicUpdated,
I_OnEncrypt, I_OnDecrypt,
@@ -1205,8 +1202,7 @@ class CoreExport ModuleManager
*/
static void ClearCallBacks(Module *m);
- /** Unloading all modules, NEVER call this when Anope isn't shutting down.
- * Ever.
+ /** Unloading all modules except the protocol module.
*/
static void UnloadAll();
diff --git a/include/services.h b/include/services.h
index 896f7bf83..f329f99ef 100644
--- a/include/services.h
+++ b/include/services.h
@@ -937,6 +937,19 @@ struct Uplink
bool ipv6;
Uplink(const Anope::string &_host, int _port, const Anope::string &_password, bool _ipv6) : host(_host), port(_port), password(_password), ipv6(_ipv6) { }
+ bool operator==(const Uplink &other) const
+ {
+ if (this->host != other.host)
+ return false;
+ if (this->port != other.port)
+ return false;
+ if (this->password != other.password)
+ return false;
+ if (this->ipv6 != other.ipv6)
+ return false;
+ return true;
+ }
+ inline bool operator!=(const Uplink &other) const { return !(*this == other); }
};
/** A class to process numbered lists (passed to most DEL/LIST/VIEW commands).
diff --git a/include/sockets.h b/include/sockets.h
index bc0c831bf..eca2635e8 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -137,27 +137,34 @@ class CoreExport SocketIO
* @param sz How much to read
* @return Number of bytes received
*/
- virtual int Recv(Socket *s, char *buf, size_t sz) const;
+ virtual int Recv(Socket *s, char *buf, size_t sz);
/** Write something to the socket
* @param s The socket
* @param buf What to write
* @return Number of bytes written
*/
- virtual int Send(Socket *s, const Anope::string &buf) const;
+ virtual int Send(Socket *s, const Anope::string &buf);
/** Accept a connection from a socket
* @param s The socket
+ * @return The new socket
+ */
+ virtual ClientSocket *Accept(ListenSocket *s);
+
+ /** Bind a socket
+ * @param s The socket
+ * @param ip The IP to bind to
+ * @param port The optional port to bind to
*/
- virtual void Accept(ListenSocket *s);
+ virtual void Bind(Socket *s, const Anope::string &ip, int port = 0);
/** Connect the socket
* @param s THe socket
* @param target IP to connect to
* @param port to connect to
- * @param bindip IP to bind to, if any
*/
- virtual void Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip = "");
+ virtual void Connect(ConnectionSocket *s, const Anope::string &target, int port);
/** Called when the socket is destructing
*/
@@ -173,6 +180,9 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
bool IPv6;
public:
+ /* Sockaddrs for bind() (if it's bound) */
+ sockaddrs bindaddr;
+
/* I/O functions used for this socket */
SocketIO *IO;
@@ -214,6 +224,12 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
*/
bool SetNonBlocking();
+ /** Bind the socket to an ip and port
+ * @param ip The ip
+ * @param port The port
+ */
+ void Bind(const Anope::string &ip, int port = 0);
+
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
@@ -291,10 +307,6 @@ class CoreExport BufferedSocket : public Socket
class CoreExport ListenSocket : public Socket
{
- protected:
- /* Sockaddrs for bindip/port */
- sockaddrs listenaddrs;
-
public:
/** Constructor
* @param bindip The IP to bind to
@@ -323,10 +335,10 @@ class CoreExport ListenSocket : public Socket
class CoreExport ConnectionSocket : public BufferedSocket
{
public:
- /* Sockaddrs for bindip (if there is one) */
- sockaddrs bindaddr;
/* Sockaddrs for connection ip/port */
sockaddrs conaddr;
+ /* True if connected */
+ bool connected;
/** Constructor
* @param ipv6 true to use IPv6
@@ -337,9 +349,27 @@ class CoreExport ConnectionSocket : public BufferedSocket
/** Connect the socket
* @param TargetHost The target host to connect to
* @param Port The target port to connect to
- * @param BindHost The host to bind to for connecting
*/
- void Connect(const Anope::string &TargetHost, int Port, const Anope::string &BindHost = "");
+ void Connect(const Anope::string &TargetHost, int Port);
+
+ /** Called when the socket is ready to be written to
+ * @return true on success, false to drop this socket
+ */
+ bool ProcessWrite();
+
+ /** Called when there is an error for this socket
+ * @return true on success, false to drop this socket
+ */
+ void ProcessError();
+
+ /** Called on a successful connect
+ */
+ virtual void OnConnect();
+
+ /** Called when a connection is not successful
+ * @param error The error
+ */
+ virtual void OnError(const Anope::string &error);
};
class CoreExport ClientSocket : public BufferedSocket
diff --git a/modules/core/db_mysql.cpp b/modules/core/db_mysql.cpp
index 193d467da..6a5ba8900 100644
--- a/modules/core/db_mysql.cpp
+++ b/modules/core/db_mysql.cpp
@@ -136,7 +136,7 @@ class DBMySQL : public Module
if (operserv)
this->AddCommand(operserv->Bot(), &commandsqlsync);
- if (uplink_server)
+ if (CurrentUplink)
OnServerConnect();
}
diff --git a/modules/core/os_restart.cpp b/modules/core/os_restart.cpp
index bda2d861c..196d0a3ab 100644
--- a/modules/core/os_restart.cpp
+++ b/modules/core/os_restart.cpp
@@ -26,7 +26,7 @@ class CommandOSRestart : public Command
{
User *u = source.u;
quitmsg = "RESTART command received from " + u->nick;
- do_restart_services();
+ quitting = save_data = restarting = true;
return MOD_CONT;
}
diff --git a/modules/core/os_shutdown.cpp b/modules/core/os_shutdown.cpp
index c67d7acb2..35f76f0c9 100644
--- a/modules/core/os_shutdown.cpp
+++ b/modules/core/os_shutdown.cpp
@@ -26,7 +26,7 @@ class CommandOSShutdown : public Command
{
User *u = source.u;
quitmsg = "SHUTDOWN command received from " + u->nick;
- shutting_down = true;
+ quitting = save_data = true;
return MOD_CONT;
}
diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl.cpp
index da6361769..30e548150 100644
--- a/modules/extra/m_ssl.cpp
+++ b/modules/extra/m_ssl.cpp
@@ -28,9 +28,16 @@ class MySSLService : public SSLService
class SSLSocketIO : public SocketIO
{
+ /** Check whether this socket has a pending connect() or accept()
+ * @return 0 if neither, -1 if connect/accept fails, -2 to wait more
+ */
+ int CheckState();
+
public:
/* The SSL socket for this socket */
SSL *sslsock;
+ /* -1 if not, 0 if waiting, 1 if true */
+ int connected, accepted;
/** Constructor
*/
@@ -42,27 +49,27 @@ class SSLSocketIO : public SocketIO
* @param sz How much to read
* @return Number of bytes received
*/
- int Recv(Socket *s, char *buf, size_t sz) const;
+ int Recv(Socket *s, char *buf, size_t sz);
/** Really write something to the socket
* @param s The socket
* @param buf What to write
* @return Number of bytes written
*/
- int Send(Socket *s, const Anope::string &buf) const;
+ int Send(Socket *s, const Anope::string &buf);
/** Accept a connection from a socket
* @param s The socket
+ * @return The new socket
*/
- void Accept(ListenSocket *s);
+ ClientSocket *Accept(ListenSocket *s);
/** Connect the socket
* @param s THe socket
* @param target IP to connect to
* @param port to connect to
- * @param bindip IP to bind to, if any
*/
- void Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip = "");
+ void Connect(ConnectionSocket *s, const Anope::string &target, int port);
/** Called when the socket is destructing
*/
@@ -144,41 +151,27 @@ class SSLModule : public Module
~SSLModule()
{
+ for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
+ {
+ Socket *s = it->second;
+ ++it;
+
+ if (dynamic_cast<SSLSocketIO *>(s->IO))
+ delete s;
+ }
+
SSL_CTX_free(client_ctx);
SSL_CTX_free(server_ctx);
}
- EventReturn OnPreServerConnect(Uplink *u, int Number)
+ void OnPreServerConnect()
{
ConfigReader config;
- if (config.ReadFlag("uplink", "ssl", "no", Number - 1))
+ if (config.ReadFlag("uplink", "ssl", "no", CurrentUplink))
{
- DNSRecord req = DNSManager::BlockingQuery(uplink_server->host, uplink_server->ipv6 ? DNS_QUERY_AAAA : DNS_QUERY_A);
-
- if (!req)
- Log() << "Unable to connect to server " << uplink_server->host << ":" << uplink_server->port << " using SSL: Invalid hostname/IP";
- else
- {
- try
- {
- new UplinkSocket(uplink_server->ipv6);
- this->service.Init(UplinkSock);
- UplinkSock->Connect(req.result, uplink_server->port, Config->LocalHost);
-
- Log() << "Connected to server " << Number << " (" << u->host << ":" << u->port << ") with SSL";
- return EVENT_ALLOW;
- }
- catch (const SocketException &ex)
- {
- Log() << "Unable to connect with SSL to server " << Number << " (" << u->host << ":" << u->port << "), " << ex.GetReason();
- }
- }
-
- return EVENT_STOP;
+ this->service.Init(UplinkSock);
}
-
- return EVENT_CONTINUE;
}
};
@@ -194,39 +187,67 @@ void MySSLService::Init(Socket *s)
s->IO = new SSLSocketIO();
}
-SSLSocketIO::SSLSocketIO()
+int SSLSocketIO::CheckState()
+{
+ if (this->connected == 0 || this->accepted == 0)
+ {
+ int ret;
+ if (this->connected == 0)
+ ret = SSL_connect(this->sslsock);
+ else if (this->accepted == 0)
+ ret = SSL_accept(this->sslsock);
+ if (ret <= 0)
+ {
+ int error = SSL_get_error(this->sslsock, ret);
+
+ if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE))
+ // Wait more
+ return -2;
+ return -1;
+ }
+
+ if (this->connected == 0)
+ this->connected = 1;
+ else if (this->accepted == 0)
+ this->accepted = 1;
+ }
+
+ return 0;
+}
+
+SSLSocketIO::SSLSocketIO() : connected(-1), accepted(-1)
{
this->sslsock = NULL;
}
-int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz) const
+int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
{
- int i = SSL_read(this->sslsock, buf, sz);
+ int i = this->CheckState();
+ if (i < 0)
+ return i;
+
+ i = SSL_read(this->sslsock, buf, sz);
TotalRead += i;
return i;
}
-int SSLSocketIO::Send(Socket *s, const Anope::string &buf) const
+int SSLSocketIO::Send(Socket *s, const Anope::string &buf)
{
- int i = SSL_write(this->sslsock, buf.c_str(), buf.length());
+ int i = this->CheckState();
+ if (i < 0)
+ return i;
+
+ i = SSL_write(this->sslsock, buf.c_str(), buf.length());
TotalWritten += i;
return i;
}
-void SSLSocketIO::Accept(ListenSocket *s)
+ClientSocket *SSLSocketIO::Accept(ListenSocket *s)
{
- sockaddrs conaddr;
-
- socklen_t size = conaddr.size();
- int newsock = accept(s->GetFD(), &conaddr.sa, &size);
-
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET -1
-#endif
- if (newsock <= 0 || newsock == INVALID_SOCKET)
- throw SocketException("Unable to accept SSL socket: " + Anope::LastError());
-
- ClientSocket *newsocket = s->OnAccept(newsock, conaddr);
+ if (s->IO == &normalSocketIO)
+ throw SocketException("Attempting to accept on uninitialized socket with SSL");
+
+ ClientSocket *newsocket = normalSocketIO.Accept(s);
me->service.Init(newsocket);
SSLSocketIO *IO = debug_cast<SSLSocketIO *>(newsocket->IO);
@@ -236,25 +257,22 @@ void SSLSocketIO::Accept(ListenSocket *s)
SSL_set_accept_state(IO->sslsock);
- if (!SSL_set_fd(IO->sslsock, newsock))
+ if (!SSL_set_fd(IO->sslsock, newsocket->GetFD()))
throw SocketException("Unable to set SSL fd");
- int ret = SSL_accept(IO->sslsock);
- if (ret <= 0)
- {
- int error = SSL_get_error(IO->sslsock, ret);
-
- if (ret != -1 || (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_READ))
- throw SocketException("Unable to accept new SSL connection: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
- }
+ IO->accepted = 0;
+ if (this->CheckState() == -1)
+ throw SocketException("Unable to accept new SSL connection: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
+
+ return newsocket;
}
-void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &TargetHost, int Port, const Anope::string &BindHost)
+void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
{
if (s->IO == &normalSocketIO)
- throw SocketException("Attempting to connect uninitialized socket with SQL");
+ throw SocketException("Attempting to connect uninitialized socket with SSL");
- normalSocketIO.Connect(s, TargetHost, Port, BindHost);
+ normalSocketIO.Connect(s, target, port);
SSLSocketIO *IO = debug_cast<SSLSocketIO *>(s->IO);
@@ -265,15 +283,9 @@ void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &TargetHost,
if (!SSL_set_fd(IO->sslsock, s->GetFD()))
throw SocketException("Unable to set SSL fd");
- int ret = SSL_connect(IO->sslsock);
-
- if (ret <= 0)
- {
- int error = SSL_get_error(IO->sslsock, ret);
-
- if (ret != -1 || (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_READ))
- throw SocketException("Unable to connect to server: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
- }
+ IO->connected = 0;
+ if (this->CheckState() == -1)
+ throw SocketException("Unable to connect to server: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
}
void SSLSocketIO::Destroy()
diff --git a/modules/extra/m_xmlrpc.cpp b/modules/extra/m_xmlrpc.cpp
index 8c0723c42..bba72c2f5 100644
--- a/modules/extra/m_xmlrpc.cpp
+++ b/modules/extra/m_xmlrpc.cpp
@@ -2,6 +2,8 @@
#include "ssl.h"
#include "xmlrpc.h"
+std::vector<XMLRPCListenSocket *> listen_sockets;
+
class MyXMLRPCClientSocket : public XMLRPCClientSocket
{
/* Used to skip the (optional) HTTP header, which we really don't care about */
@@ -85,7 +87,17 @@ class MyXMLRPCClientSocket : public XMLRPCClientSocket
class MyXMLRPCListenSocket : public XMLRPCListenSocket
{
public:
- MyXMLRPCListenSocket(const Anope::string &bindip, int port, bool ipv6, const Anope::string &u, const Anope::string &p, const std::vector<Anope::string> &a) : XMLRPCListenSocket(bindip, port, ipv6, u, p, a) { }
+ MyXMLRPCListenSocket(const Anope::string &bindip, int port, bool ipv6, const Anope::string &u, const Anope::string &p, const std::vector<Anope::string> &a) : XMLRPCListenSocket(bindip, port, ipv6, u, p, a)
+ {
+ listen_sockets.push_back(this);
+ }
+
+ ~MyXMLRPCListenSocket()
+ {
+ std::vector<XMLRPCListenSocket *>::iterator it = std::find(listen_sockets.begin(), listen_sockets.end(), this);
+ if (it != listen_sockets.end())
+ listen_sockets.erase(it);
+ }
ClientSocket *OnAccept(int fd, const sockaddrs &addr)
{
@@ -208,7 +220,6 @@ class ModuleXMLRPC;
static ModuleXMLRPC *me;
class ModuleXMLRPC : public Module
{
- std::vector<MyXMLRPCListenSocket *> listen_sockets;
service_reference<SSLService> sslref;
public:
@@ -229,15 +240,16 @@ class ModuleXMLRPC : public Module
~ModuleXMLRPC()
{
/* Clean up our sockets and our listening sockets */
- for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end; ++it)
+ for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
{
Socket *s = it->second;
+ ++it;
if (s->Type == SOCKTYPE_CLIENT)
{
ClientSocket *cs = debug_cast<ClientSocket *>(s);
- for (unsigned i = 0; i < this->listen_sockets.size(); ++i)
- if (cs->LS == this->listen_sockets[i])
+ for (unsigned i = 0; i < listen_sockets.size(); ++i)
+ if (cs->LS == listen_sockets[i])
{
delete cs;
break;
@@ -245,18 +257,18 @@ class ModuleXMLRPC : public Module
}
}
- for (unsigned i = 0; i < this->listen_sockets.size(); ++i)
- delete this->listen_sockets[i];
- this->listen_sockets.clear();
+ for (unsigned i = 0; i < listen_sockets.size(); ++i)
+ delete listen_sockets[i];
+ listen_sockets.clear();
}
void OnReload()
{
ConfigReader config;
- for (unsigned i = 0; i < this->listen_sockets.size(); ++i)
- delete this->listen_sockets[i];
- this->listen_sockets.clear();
+ for (unsigned i = 0; i < listen_sockets.size(); ++i)
+ delete listen_sockets[i];
+ listen_sockets.clear();
for (int i = 0; i < config.Enumerate("m_xmlrpc"); ++i)
{
@@ -282,10 +294,7 @@ class ModuleXMLRPC : public Module
{
MyXMLRPCListenSocket *xmls = new MyXMLRPCListenSocket(bindip, port, ipv6, username, password, allowed_vector);
if (ssl)
- {
sslref->Init(xmls);
- }
- this->listen_sockets.push_back(xmls);
}
catch (const SocketException &ex)
{
diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp
index 92aee74fb..29f16004e 100644
--- a/modules/protocol/bahamut.cpp
+++ b/modules/protocol/bahamut.cpp
@@ -232,7 +232,7 @@ class BahamutIRCdProto : public IRCDProto
void SendConnect()
{
- bahamut_cmd_pass(uplink_server->password);
+ bahamut_cmd_pass(Config->Uplinks[CurrentUplink]->password);
bahamut_cmd_capab();
SendServer(Me);
bahamut_cmd_svinfo();
diff --git a/modules/protocol/inspircd-ts6.h b/modules/protocol/inspircd-ts6.h
index d76dc27c2..cf93865f8 100644
--- a/modules/protocol/inspircd-ts6.h
+++ b/modules/protocol/inspircd-ts6.h
@@ -124,7 +124,7 @@ class InspIRCdTS6Proto : public IRCDProto
/* SERVER services-dev.chatspike.net password 0 :Description here */
void SendServer(const Server *server)
{
- send_cmd("", "SERVER %s %s %d %s :%s", server->GetName().c_str(), uplink_server ? uplink_server->password.c_str() : "none", server->GetHops(), server->GetSID().c_str(), server->GetDescription().c_str());
+ send_cmd("", "SERVER %s %s %d %s :%s", server->GetName().c_str(), Config->Uplinks[CurrentUplink]->password.c_str(), server->GetHops(), server->GetSID().c_str(), server->GetDescription().c_str());
}
/* JOIN */
diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp
index 5ab55ab07..a382d4006 100644
--- a/modules/protocol/inspircd11.cpp
+++ b/modules/protocol/inspircd11.cpp
@@ -199,7 +199,7 @@ class InspIRCdProto : public IRCDProto
void SendConnect()
{
- inspircd_cmd_pass(uplink_server->password);
+ inspircd_cmd_pass(Config->Uplinks[CurrentUplink]->password);
SendServer(Me);
send_cmd("", "BURST");
Module *enc = ModuleManager::FindFirstOf(ENCRYPTION);
diff --git a/modules/protocol/plexus.cpp b/modules/protocol/plexus.cpp
index 04095e5a2..5e6c67781 100644
--- a/modules/protocol/plexus.cpp
+++ b/modules/protocol/plexus.cpp
@@ -157,7 +157,7 @@ class PlexusProto : public IRCDProto
void SendConnect()
{
- plexus_cmd_pass(uplink_server->password);
+ plexus_cmd_pass(Config->Uplinks[CurrentUplink]->password);
plexus_cmd_capab();
/* Make myself known to myself in the serverlist */
SendServer(Me);
diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp
index d6cfc761f..2833c52b7 100644
--- a/modules/protocol/ratbox.cpp
+++ b/modules/protocol/ratbox.cpp
@@ -160,7 +160,7 @@ class RatboxProto : public IRCDProto
void SendConnect()
{
- ratbox_cmd_pass(uplink_server->password);
+ ratbox_cmd_pass(Config->Uplinks[CurrentUplink]->password);
ratbox_cmd_capab();
/* Make myself known to myself in the serverlist */
SendServer(Me);
diff --git a/modules/protocol/unreal.cpp b/modules/protocol/unreal.cpp
index cb7a54d61..e07b97af0 100644
--- a/modules/protocol/unreal.cpp
+++ b/modules/protocol/unreal.cpp
@@ -228,7 +228,7 @@ class UnrealIRCdProto : public IRCDProto
void SendConnect()
{
unreal_cmd_capab();
- unreal_cmd_pass(uplink_server->password);
+ unreal_cmd_pass(Config->Uplinks[CurrentUplink]->password);
SendServer(Me);
}
diff --git a/src/config.cpp b/src/config.cpp
index 671cf3ed7..7d3efcb91 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -563,7 +563,7 @@ bool InitUplinks(ServerConfig *config, const Anope::string &)
{
if (!config->Uplinks.empty())
{
- std::list<Uplink *>::iterator curr_uplink = config->Uplinks.begin(), end_uplink = config->Uplinks.end();
+ std::vector<Uplink *>::iterator curr_uplink = config->Uplinks.begin(), end_uplink = config->Uplinks.end();
for (; curr_uplink != end_uplink; ++curr_uplink)
delete *curr_uplink;
}
@@ -1033,7 +1033,6 @@ ConfigItems::ConfigItems(ServerConfig *conf)
{"options", "mlock", "+nrt", new ValueContainerString(&conf->MLock), DT_STRING, NoValidation},
{"options", "nomlock", "", new ValueContainerString(&conf->NoMLock), DT_STRING, NoValidation},
{"options", "botmodes", "", new ValueContainerString(&conf->BotModes), DT_STRING, NoValidation},
- {"options", "maxretries", "10", new ValueContainerUInt(&conf->MaxRetries), DT_UINTEGER, NoValidation},
{"options", "retrywait", "60", new ValueContainerInt(&conf->RetryWait), DT_INTEGER, ValidateNotZero},
{"options", "hideprivilegedcommands", "no", new ValueContainerBool(&conf->HidePrivilegedCommands), DT_BOOLEAN, NoValidation},
{"nickserv", "nick", "NickServ", new ValueContainerString(&conf->s_NickServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty},
diff --git a/src/dns.cpp b/src/dns.cpp
index 7475545c0..4c1178865 100644
--- a/src/dns.cpp
+++ b/src/dns.cpp
@@ -42,6 +42,11 @@ void DNSRequest::Process()
{
Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << this->address << ", of type " << this->QT;
+ if (!DNSEngine)
+ throw SocketException("DNSEngine has not been initialized");
+ else if (!DNSEngine->sock || !DNSEngine->sock->connected)
+ throw SocketException("Connection to nameserver has not been established");
+
if (this->use_cache && DNSEngine->CheckCache(this))
{
Log(LOG_DEBUG_2) << "Resolver: Using cached result";
@@ -236,7 +241,8 @@ DNSSocket::~DNSSocket()
delete DNSEngine->packets[i - 1];
DNSEngine->packets.clear();
Log(LOG_NORMAL, "dns") << "Resolver: Lost connection to nameserver";
- DNSEngine->sock = NULL;
+ if (DNSEngine)
+ DNSEngine->sock = NULL;
}
int DNSSocket::SendTo(const unsigned char *buf, size_t len) const
@@ -497,7 +503,10 @@ bool DNSSocket::ProcessRead()
bool DNSSocket::ProcessWrite()
{
- Log(LOG_DEBUG_2) << "Resolver: Writing to UDP socket";
+ if (!this->connected)
+ return ConnectionSocket::ProcessWrite();
+
+ Log(LOG_DEBUG_2) << "Resolver: Writing to DNS socket";
bool cont = true;
for (unsigned i = DNSEngine->packets.size(); cont && i > 0; --i)
@@ -517,6 +526,16 @@ bool DNSSocket::ProcessWrite()
return cont;
}
+void DNSSocket::OnConnect()
+{
+ Log(LOG_DEBUG_2) << "Resolver: Successfully connected to nameserver";
+}
+
+void DNSSocket::OnError(const Anope::string &error)
+{
+ Log() << "Resolver: Error connecting to nameserver: " << error;
+}
+
DNSManager::DNSManager() : Timer(300, Anope::CurTime, true)
{
this->sock = NULL;
diff --git a/src/init.cpp b/src/init.cpp
index ad95e4d4b..7fa684336 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -376,7 +376,6 @@ void Init(int ac, char **av)
/* Announce ourselves to the logfile. */
Log() << "Anope " << Anope::Version() << " starting up" << (debug || readonly ? " (options:" : "") << (debug ? " debug" : "") << (readonly ? " readonly" : "") << (debug || readonly ? ")" : "");
- start_time = Anope::CurTime;
/* Set signal handlers. Catch certain signals to let us do things or
* panic as necessary, and ignore all others.
diff --git a/src/main.cpp b/src/main.cpp
index 380240dbb..199b3162f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -55,8 +55,8 @@ Anope::string binary_dir; /* Used to store base path for Anope */
/* Set to 1 if we are to quit */
bool quitting = false;
-/* Set to 1 if we are to quit after saving databases */
-bool shutting_down = false;
+/* Set to true if we are restarting */
+bool restarting = false;
/* Contains a message as to why services is terminating */
Anope::string quitmsg;
@@ -65,10 +65,7 @@ Anope::string quitmsg;
bool save_data = false;
/* At what time were we started? */
-time_t start_time;
-
-/* Parameters and environment */
-char **my_av, **my_envp;
+time_t start_time = time(NULL);
time_t Anope::CurTime = time(NULL);
@@ -92,123 +89,125 @@ class UpdateTimer : public Timer
};
ConnectionSocket *UplinkSock = NULL;
+int CurrentUplink = 0;
-UplinkSocket::UplinkSocket(bool ipv6) : ConnectionSocket(ipv6)
-{
- UplinkSock = this;
-}
+static void Connect();
-UplinkSocket::~UplinkSocket()
+class ReconnectTimer : public Timer
{
- SocketEngine::Process();
- UplinkSock = NULL;
-}
+ public:
+ ReconnectTimer(int wait) : Timer(wait) { }
-bool UplinkSocket::Read(const Anope::string &buf)
+ void Tick(time_t)
+ {
+ Connect();
+ }
+};
+
+class UplinkSocket : public ConnectionSocket
{
- process(buf);
- return true;
-}
+ public:
+ UplinkSocket() : ConnectionSocket(Config->Uplinks[CurrentUplink]->ipv6)
+ {
+ UplinkSock = this;
+ }
-/*************************************************************************/
+ ~UplinkSocket()
+ {
+ if (Me && Me->GetUplink() && Me->GetUplink()->IsSynced())
+ {
+ FOREACH_MOD(I_OnServerDisconnect, OnServerDisconnect());
-void save_databases()
-{
- if (readonly)
- return;
+ /* Send a quit for all of our bots */
+ for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it)
+ {
+ BotInfo *bi = it->second;
+
+ /* Don't use quitmsg here, it may contain information you don't want people to see */
+ ircdproto->SendQuit(bi, "Shutting down");
+ /* Erase bots from the user list so they don't get nuked later on */
+ UserListByNick.erase(bi->nick);
+ if (!bi->GetUID().empty())
+ UserListByUID.erase(bi->GetUID());
+ }
- EventReturn MOD_RESULT;
- FOREACH_RESULT(I_OnSaveDatabase, OnSaveDatabase());
- Log(LOG_DEBUG) << "Saving databases";
-}
+ /* Clear all of our users, but not our bots */
+ for (Anope::insensitive_map<User *>::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();)
+ {
+ User *u = it->second;
+ ++it;
-/*************************************************************************/
+ if (u->server != Me)
+ delete u;
+ }
-/* Restarts services */
-void do_restart_services()
-{
- if (!readonly)
- {
- save_databases();
- }
- Log() << "Restarting";
+ ircdproto->SendSquit(Config->ServerName, quitmsg);
- if (quitmsg.empty())
- quitmsg = "Restarting";
+ this->ProcessWrite(); // Write out the last bit
+ }
- FOREACH_MOD(I_OnRestart, OnRestart());
- ModuleManager::UnloadAll();
+ Me->SetFlag(SERVER_SYNCING);
+ for (unsigned i = Me->GetLinks().size(); i > 0; --i)
+ if (!Me->GetLinks()[i - 1]->HasFlag(SERVER_JUPED))
+ delete Me->GetLinks()[i - 1];
- /* Send a quit for all of our bots */
- for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it)
- {
- BotInfo *bi = it->second;
-
- /* Don't use quitmsg here, it may contain information you don't want people to see */
- ircdproto->SendQuit(bi, "Restarting");
- /* Erase bots from the user list so they don't get nuked later on */
- UserListByNick.erase(bi->nick);
- if (!bi->GetUID().empty())
- UserListByUID.erase(bi->GetUID());
- }
+ UplinkSock = NULL;
- ircdproto->SendSquit(Config->ServerName, quitmsg);
- delete UplinkSock;
- SocketEngine::Shutdown();
+ if (!quitting)
+ {
+ int Retry = Config->RetryWait;
+ if (Retry <= 0)
+ Retry = 60;
- chdir(binary_dir.c_str());
- my_av[0] = const_cast<char *>(("./" + services_bin).c_str());
- execve(services_bin.c_str(), my_av, my_envp);
- if (!readonly)
- {
- throw FatalException("Restart failed");
+ Log() << "Retrying in " << Retry << " seconds";
+ new ReconnectTimer(Retry);
+ }
}
- exit(1);
-}
+ bool Read(const Anope::string &buf)
+ {
+ process(buf);
+ return true;
+ }
-/*************************************************************************/
+ void OnConnect()
+ {
+ Log() << "Successfully connected to " << Config->Uplinks[CurrentUplink]->host << ":" << Config->Uplinks[CurrentUplink]->port;
+ ircdproto->SendConnect();
+ FOREACH_MOD(I_OnServerConnect, OnServerConnect());
+ }
-/* Terminates services */
+ void OnError(const Anope::string &error)
+ {
+ Log() << "Unable to connect to server " << Config->Uplinks[CurrentUplink]->host << ":" << Config->Uplinks[CurrentUplink]->port << (!error.empty() ? (": " + error) : "");
+ this->SetFlag(SF_DEAD);
+ }
+};
-static void services_shutdown()
+static void Connect()
{
- if (quitmsg.empty())
- quitmsg = "Terminating, reason unknown";
- Log() << quitmsg;
+ if (static_cast<unsigned>(++CurrentUplink) >= Config->Uplinks.size())
+ CurrentUplink = 0;
- FOREACH_MOD(I_OnShutdown, OnShutdown());
- ModuleManager::UnloadAll();
+ Uplink *u = Config->Uplinks[CurrentUplink];
- if (started && UplinkSock)
- {
- /* Send a quit for all of our bots */
- for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it)
- {
- BotInfo *bi = it->second;
-
- /* Don't use quitmsg here, it may contain information you don't want people to see */
- ircdproto->SendQuit(bi, "Shutting down");
- /* Erase bots from the user list so they don't get nuked later on */
- UserListByNick.erase(bi->nick);
- if (!bi->GetUID().empty())
- UserListByUID.erase(bi->GetUID());
- }
+ new UplinkSocket();
+ if (!Config->LocalHost.empty())
+ UplinkSock->Bind(Config->LocalHost);
+ FOREACH_MOD(I_OnPreServerConnect, OnPreServerConnect());
+ UplinkSock->Connect(u->host, u->port);
+}
- ircdproto->SendSquit(Config->ServerName, quitmsg);
+/*************************************************************************/
- for (Anope::insensitive_map<User *>::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();)
- {
- User *u = it->second;
- ++it;
- delete u;
- }
- }
- delete UplinkSock;
- SocketEngine::Shutdown();
+void save_databases()
+{
+ if (readonly)
+ return;
- /* just in case they weren't all removed at least run once */
- ModuleManager::CleanupRuntimeDirectory();
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnSaveDatabase, OnSaveDatabase());
+ Log(LOG_DEBUG) << "Saving databases";
}
/*************************************************************************/
@@ -314,201 +313,132 @@ Anope::string GetFullProgDir(const Anope::string &argv0)
/*************************************************************************/
-static bool Connect()
-{
- /* Connect to the remote server */
- int servernum = 1;
- for (std::list<Uplink *>::iterator curr_uplink = Config->Uplinks.begin(), end_uplink = Config->Uplinks.end(); curr_uplink != end_uplink; ++curr_uplink, ++servernum)
- {
- uplink_server = *curr_uplink;
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(I_OnPreServerConnect, OnPreServerConnect(*curr_uplink, servernum));
- if (MOD_RESULT != EVENT_CONTINUE)
- {
- if (MOD_RESULT == EVENT_STOP)
- continue;
- return true;
- }
-
- DNSRecord req = DNSManager::BlockingQuery(uplink_server->host, uplink_server->ipv6 ? DNS_QUERY_AAAA : DNS_QUERY_A);
-
- if (!req)
- {
- Log() << "Unable to connect to server " << servernum << " (" << uplink_server->host << ":" << uplink_server->port << "): Invalid hostname/IP";
- continue;
- }
-
- try
- {
- new UplinkSocket(uplink_server->ipv6);
- UplinkSock->Connect(req.result, uplink_server->port, Config->LocalHost);
- }
- catch (const SocketException &ex)
- {
- Log() << "Unable to connect to server " << servernum << " (" << uplink_server->host << ":" << uplink_server->port << "): " << ex.GetReason();
- continue;
- }
-
- Log() << "Connected to server " << servernum << " (" << uplink_server->host << ":" << uplink_server->port << ")";
- return true;
- }
-
- uplink_server = NULL;
-
- return false;
-}
-
-/*************************************************************************/
-
/* Main routine. (What does it look like? :-) ) */
int main(int ac, char **av, char **envp)
{
- try
- {
- my_av = av;
- my_envp = envp;
+ int return_code = 0;
- char cwd[PATH_MAX] = "";
+ char cwd[PATH_MAX] = "";
#ifdef _WIN32
- GetCurrentDirectory(PATH_MAX, cwd);
+ GetCurrentDirectory(PATH_MAX, cwd);
#else
- getcwd(cwd, PATH_MAX);
+ getcwd(cwd, PATH_MAX);
#endif
- orig_cwd = cwd;
+ orig_cwd = cwd;
#ifndef _WIN32
- /* If we're root, issue a warning now */
- if (!getuid() && !getgid())
- {
- fprintf(stderr, "WARNING: You are currently running Anope as the root superuser. Anope does not\n");
- fprintf(stderr, " require root privileges to run, and it is discouraged that you run Anope\n");
- fprintf(stderr, " as the root superuser.\n");
- }
+ /* If we're root, issue a warning now */
+ if (!getuid() && !getgid())
+ {
+ fprintf(stderr, "WARNING: You are currently running Anope as the root superuser. Anope does not\n");
+ fprintf(stderr, " require root privileges to run, and it is discouraged that you run Anope\n");
+ fprintf(stderr, " as the root superuser.\n");
+ }
#endif
- binary_dir = GetFullProgDir(av[0]);
- if (binary_dir[binary_dir.length() - 1] == '.')
- binary_dir = binary_dir.substr(0, binary_dir.length() - 2);
+ binary_dir = GetFullProgDir(av[0]);
+ if (binary_dir[binary_dir.length() - 1] == '.')
+ binary_dir = binary_dir.substr(0, binary_dir.length() - 2);
#ifdef _WIN32
- Anope::string::size_type n = binary_dir.rfind('\\');
- services_dir = binary_dir.substr(0, n) + "\\data";
+ Anope::string::size_type n = binary_dir.rfind('\\');
+ services_dir = binary_dir.substr(0, n) + "\\data";
#else
- Anope::string::size_type n = binary_dir.rfind('/');
- services_dir = binary_dir.substr(0, n) + "/data";
+ Anope::string::size_type n = binary_dir.rfind('/');
+ services_dir = binary_dir.substr(0, n) + "/data";
#endif
- /* Clean out the module runtime directory prior to running, just in case files were left behind during a previous run */
- ModuleManager::CleanupRuntimeDirectory();
+ /* Clean out the module runtime directory prior to running, just in case files were left behind during a previous run */
+ ModuleManager::CleanupRuntimeDirectory();
+ try
+ {
/* General initialization first */
Init(ac, av);
+ }
+ catch (const FatalException &ex)
+ {
+ Log() << ex.GetReason();
+ return -1;
+ }
- /* If the first connect fails give up, don't sit endlessly trying to reconnect */
- if (!Connect())
- {
- Log() << "Can't connect to any servers";
- return 0;
- }
+ try
+ {
+ Connect();
+ }
+ catch (const SocketException &ex)
+ {
+ Log() << ex.GetReason();
+ ModuleManager::UnloadAll();
+ SocketEngine::Shutdown();
+ for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
+ ModuleManager::UnloadModule(m, NULL);
+ ModuleManager::CleanupRuntimeDirectory();
+ return -1;
+ }
- ircdproto->SendConnect();
- FOREACH_MOD(I_OnServerConnect, OnServerConnect());
+ started = true;
- started = true;
+ /* Set up timers */
+ time_t last_check = Anope::CurTime;
+ UpdateTimer updateTimer(Config->UpdateTimeout);
- /* Set up timers */
- time_t last_check = Anope::CurTime;
- UpdateTimer updateTimer(Config->UpdateTimeout);
+ /*** Main loop. ***/
+ while (!quitting)
+ {
+ Log(LOG_DEBUG_2) << "Top of main loop";
- /*** Main loop. ***/
- while (!quitting)
+ if (Anope::CurTime - last_check >= Config->TimeoutCheck)
{
- while (!quitting && UplinkSock)
- {
- Log(LOG_DEBUG_2) << "Top of main loop";
-
- if (!readonly && (save_data || shutting_down))
- {
- if (shutting_down)
- ircdproto->SendGlobops(NULL, "Updating databases on shutdown, please wait.");
- save_databases();
- save_data = false;
- }
-
- if (shutting_down)
- {
- quitting = true;
- break;
- }
+ TimerManager::TickTimers(Anope::CurTime);
+ last_check = Anope::CurTime;
+ }
- if (Anope::CurTime - last_check >= Config->TimeoutCheck)
- {
- TimerManager::TickTimers(Anope::CurTime);
- last_check = Anope::CurTime;
- }
+ /* Free up any finished threads */
+ threadEngine.Process();
- /* Free up any finished threads */
- threadEngine.Process();
+ /* Process any modes that need to be (un)set */
+ if (Me->IsSynced())
+ ModeManager::ProcessModes();
- /* Process any modes that need to be (un)set */
- if (Me != NULL && Me->IsSynced())
- ModeManager::ProcessModes();
+ /* Process the socket engine */
+ SocketEngine::Process();
+ }
- /* Process the socket engine */
- SocketEngine::Process();
- }
+ if (save_data)
+ {
+ ircdproto->SendGlobops(NULL, "Updating databases on shutdown, please wait.");
+ save_databases();
+ save_data = false;
+ }
- if (quitting)
- /* Disconnect and exit */
- services_shutdown();
- else
- {
- FOREACH_MOD(I_OnServerDisconnect, OnServerDisconnect());
+ if (restarting)
+ {
+ FOREACH_MOD(I_OnRestart, OnRestart());
+ }
+ else
+ {
+ FOREACH_MOD(I_OnShutdown, OnShutdown());
+ }
- /* Clear all of our users, but not our bots */
- for (Anope::insensitive_map<User *>::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();)
- {
- User *u = it->second;
- ++it;
+ if (quitmsg.empty())
+ quitmsg = "Terminating, reason unknown";
+ Log() << quitmsg;
- if (u->server != Me)
- delete u;
- }
+ ModuleManager::UnloadAll();
+ SocketEngine::Shutdown();
+ for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
+ ModuleManager::UnloadModule(m, NULL);
- Me->SetFlag(SERVER_SYNCING);
- for (unsigned i = Me->GetLinks().size(); i > 0; --i)
- if (!Me->GetLinks()[i - 1]->HasFlag(SERVER_JUPED))
- delete Me->GetLinks()[i - 1];
+ ModuleManager::CleanupRuntimeDirectory();
- unsigned j = 0;
- for (; j < (Config->MaxRetries ? Config->MaxRetries : j + 1); ++j)
- {
- Log() << "Disconnected from the server, retrying in " << Config->RetryWait << " seconds";
-
- sleep(Config->RetryWait);
- if (Connect())
- {
- ircdproto->SendConnect();
- FOREACH_MOD(I_OnServerConnect, OnServerConnect());
- break;
- }
- }
- if (Config->MaxRetries && j == Config->MaxRetries)
- {
- Log() << "Max connection retry limit exceeded";
- quitting = true;
- }
- }
- }
- }
- catch (const FatalException &ex)
+ if (restarting)
{
- if (!ex.GetReason().empty())
- Log(LOG_TERMINAL) << ex.GetReason();
- if (started)
- services_shutdown();
- return -1;
+ chdir(binary_dir.c_str());
+ av[0] = const_cast<char *>(("./" + services_bin).c_str());
+ execve(services_bin.c_str(), av, envp);
+ Log() << "Restart failed";
+ return_code = -1;
}
return 0;
diff --git a/src/messages.cpp b/src/messages.cpp
index f8d893eca..ed9e572ce 100644
--- a/src/messages.cpp
+++ b/src/messages.cpp
@@ -25,7 +25,7 @@ bool OnStats(const Anope::string &source, const std::vector<Anope::string> &para
if (u && u->HasMode(UMODE_OPER))
{
ircdproto->SendNumeric(Config->ServerName, 211, source, "Server SendBuf SentBytes SentMsgs RecvBuf RecvBytes RecvMsgs ConnTime");
- ircdproto->SendNumeric(Config->ServerName, 211, source, "%s %d %d %d %d %d %d %ld", uplink_server->host.c_str(), UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, static_cast<long>(Anope::CurTime - start_time));
+ ircdproto->SendNumeric(Config->ServerName, 211, source, "%s %d %d %d %d %d %d %ld", Config->Uplinks[CurrentUplink]->host.c_str(), UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, static_cast<long>(Anope::CurTime - start_time));
}
ircdproto->SendNumeric(Config->ServerName, 219, source, "%c :End of /STATS report.", params[0][0]);
diff --git a/src/misc.cpp b/src/misc.cpp
index fff224eed..966af359e 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -843,6 +843,15 @@ void Anope::Unhex(const Anope::string &src, char *dest)
dest[destpos] = 0;
}
+int Anope::LastErrorCode()
+{
+#ifndef _WIN32
+ return errno;
+#else
+ return GetLastError();
+#endif
+}
+
const Anope::string Anope::LastError()
{
#ifndef _WIN32
diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp
index e2f837f0f..1c4e07eef 100644
--- a/src/modulemanager.cpp
+++ b/src/modulemanager.cpp
@@ -308,6 +308,8 @@ ModuleReturn ModuleManager::DeleteModule(Module *m)
ano_module_t handle = m->handle;
Anope::string filename = m->filename;
+ Log(LOG_DEBUG) << "Unloading module " << m->name;
+
ano_modclearerr();
void (*destroy_func)(Module *m) = function_cast<void (*)(Module *)>(dlsym(m->handle, "AnopeFini"));
const char *err = ano_moderr();
@@ -471,14 +473,14 @@ void ModuleManager::ClearCallBacks(Module *m)
delete m->CallBacks.front();
}
-/** Unloading all modules, NEVER call this when Anope isn't shutting down.
- * Ever.
+/** Unloading all modules except the protocol module.
*/
void ModuleManager::UnloadAll()
{
std::vector<Anope::string> modules[MT_END];
for (std::list<Module *>::iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
- modules[(*it)->type].push_back((*it)->name);
+ if ((*it)->type != PROTOCOL)
+ modules[(*it)->type].push_back((*it)->name);
for (size_t i = MT_BEGIN + 1; i != MT_END; ++i)
for (unsigned j = 0; j < modules[i].size(); ++j)
diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp
index 0ced8e71e..316696f54 100644
--- a/src/socketengines/socketengine_epoll.cpp
+++ b/src/socketengines/socketengine_epoll.cpp
@@ -30,6 +30,8 @@ void SocketEngine::Init()
void SocketEngine::Shutdown()
{
+ Process();
+
for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end; ++it)
delete it->second;
Sockets.clear();
diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp
index b8eef91b8..3202bbe29 100644
--- a/src/socketengines/socketengine_poll.cpp
+++ b/src/socketengines/socketengine_poll.cpp
@@ -37,6 +37,8 @@ void SocketEngine::Init()
void SocketEngine::Shutdown()
{
+ Process();
+
for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end; ++it)
delete it->second;
Sockets.clear();
diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp
index 43b9b17cc..e23046b79 100644
--- a/src/socketengines/socketengine_select.cpp
+++ b/src/socketengines/socketengine_select.cpp
@@ -13,6 +13,8 @@ void SocketEngine::Init()
void SocketEngine::Shutdown()
{
+ Process();
+
for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end; ++it)
delete it->second;
Sockets.clear();
diff --git a/src/sockets.cpp b/src/sockets.cpp
index 96acbe981..c9758cb12 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -251,7 +251,7 @@ bool cidr::match(sockaddrs &other)
* @param sz How much to read
* @return Number of bytes received
*/
-int SocketIO::Recv(Socket *s, char *buf, size_t sz) const
+int SocketIO::Recv(Socket *s, char *buf, size_t sz)
{
size_t i = recv(s->GetFD(), buf, sz, 0);
TotalRead += i;
@@ -263,7 +263,7 @@ int SocketIO::Recv(Socket *s, char *buf, size_t sz) const
* @param buf What to write
* @return Number of bytes written
*/
-int SocketIO::Send(Socket *s, const Anope::string &buf) const
+int SocketIO::Send(Socket *s, const Anope::string &buf)
{
size_t i = send(s->GetFD(), buf.c_str(), buf.length(), 0);
TotalWritten += i;
@@ -272,8 +272,9 @@ int SocketIO::Send(Socket *s, const Anope::string &buf) const
/** Accept a connection from a socket
* @param s The socket
+ * @return The new client socket
*/
-void SocketIO::Accept(ListenSocket *s)
+ClientSocket *SocketIO::Accept(ListenSocket *s)
{
sockaddrs conaddr;
@@ -285,32 +286,44 @@ void SocketIO::Accept(ListenSocket *s)
#endif
if (newsock > 0 && newsock != INVALID_SOCKET)
- s->OnAccept(newsock, conaddr);
+ return s->OnAccept(newsock, conaddr);
else
throw SocketException("Unable to accept connection: " + Anope::LastError());
}
+/** Bind a socket
+ * @param s The socket
+ * @param ip The IP to bind to
+ * @param port The optional port to bind to
+ */
+void SocketIO::Bind(Socket *s, const Anope::string &ip, int port)
+{
+ s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port);
+ if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1)
+ throw SocketException("Unable to bind to address: " + Anope::LastError());
+}
+
/** Connect the socket
* @param s THe socket
* @param target IP to connect to
* @param port to connect to
- * @param bindip IP to bind to, if any
*/
-void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip)
+void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
{
- s->bindaddr.clear();
- s->conaddr.clear();
-
- if (!bindip.empty())
+ s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
+ int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
+ if (c == -1)
{
- s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, bindip, 0);
- if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + Anope::LastError());
+ if (Anope::LastErrorCode() != EINPROGRESS)
+ throw SocketException("Error connecting to server: " + Anope::LastError());
+ else
+ SocketEngine::MarkWritable(s);
+ }
+ else
+ {
+ s->OnConnect();
+ s->connected = true;
}
-
- s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
- if (connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size()) == -1 && errno != EINPROGRESS)
- throw SocketException(Anope::string("Error connecting to server: ") + Anope::LastError());
}
/** Empty constructor, used for things such as the pipe socket
@@ -335,6 +348,7 @@ Socket::Socket(int sock, bool ipv6, int type) : Flags<SocketFlag, 2>(SocketFlagS
this->Sock = socket(this->IPv6 ? AF_INET6 : AF_INET, type, 0);
else
this->Sock = sock;
+ this->SetNonBlocking();
SocketEngine::AddSocket(this);
}
@@ -391,6 +405,15 @@ bool Socket::SetNonBlocking()
#endif
}
+/** Bind the socket to an ip and port
+ * @param ip The ip
+ * @param port The port
+ */
+void Socket::Bind(const Anope::string &ip, int port)
+{
+ this->IO->Bind(this, ip, port);
+}
+
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
@@ -445,7 +468,9 @@ bool BufferedSocket::ProcessRead()
char tbuffer[NET_BUFSIZE] = "";
RecvLen = this->IO->Recv(this, tbuffer, sizeof(tbuffer) - 1);
- if (RecvLen <= 0)
+ if (RecvLen == -2)
+ return true;
+ else if (RecvLen <= 0)
return false;
Anope::string sbuffer = this->extrabuf;
@@ -482,10 +507,10 @@ bool BufferedSocket::ProcessRead()
*/
bool BufferedSocket::ProcessWrite()
{
- if (this->WriteBuffer.empty())
- return true;
int count = this->IO->Send(this, this->WriteBuffer);
- if (count <= -1)
+ if (count == -2)
+ return true;
+ else if (count <= -1)
return false;
this->WriteBuffer = this->WriteBuffer.substr(count);
if (this->WriteBuffer.empty())
@@ -557,10 +582,8 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool ipv6) : S
this->Type = SOCKTYPE_LISTEN;
this->SetNonBlocking();
- this->listenaddrs.pton(IPv6 ? AF_INET6 : AF_INET, bindip, port);
-
- if (bind(Sock, &this->listenaddrs.sa, this->listenaddrs.size()) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + Anope::LastError());
+ this->bindaddr.pton(IPv6 ? AF_INET6 : AF_INET, bindip, port);
+ this->IO->Bind(this, bindip, port);
if (listen(Sock, 5) == -1)
throw SocketException(Anope::string("Unable to listen: ") + Anope::LastError());
@@ -601,7 +624,7 @@ ClientSocket *ListenSocket::OnAccept(int fd, const sockaddrs &addr)
* @param ipv6 true to use IPv6
* @param type The socket type, defaults to SOCK_STREAM
*/
-ConnectionSocket::ConnectionSocket(bool ipv6, int type) : BufferedSocket(0, ipv6, type)
+ConnectionSocket::ConnectionSocket(bool ipv6, int type) : BufferedSocket(0, ipv6, type), connected(false)
{
this->Type = SOCKTYPE_CONNECTION;
}
@@ -609,19 +632,58 @@ ConnectionSocket::ConnectionSocket(bool ipv6, int type) : BufferedSocket(0, ipv6
/** Connect the socket
* @param TargetHost The target host to connect to
* @param Port The target port to connect to
- * @param BindHost The host to bind to for connecting
*/
-void ConnectionSocket::Connect(const Anope::string &TargetHost, int Port, const Anope::string &BindHost)
+void ConnectionSocket::Connect(const Anope::string &TargetHost, int Port)
{
- try
- {
- this->IO->Connect(this, TargetHost, Port, BindHost);
- }
- catch (const SocketException &)
+ this->IO->Connect(this, TargetHost, Port);
+}
+
+/** Called when the socket is ready to be written to
+ * @return true on success, false to drop this socket
+ */
+bool ConnectionSocket::ProcessWrite()
+{
+ if (!this->connected)
{
- delete this;
- throw;
+ SocketEngine::ClearWritable(this);
+
+ int optval = 0;
+ socklen_t optlen = sizeof(optval);
+ if (!getsockopt(this->GetFD(), SOL_SOCKET, SO_ERROR, &optval, &optlen) && !optval)
+ {
+ this->OnConnect();
+ this->connected = true;
+ return true;
+ }
+
+ errno = optval;
+ this->OnError(Anope::LastError());
+ return false;
}
+
+ return BufferedSocket::ProcessWrite();
+}
+
+/** Called when there is an error for this socket
+ * @return true on success, false to drop this socket
+ */
+void ConnectionSocket::ProcessError()
+{
+ if (!this->connected)
+ this->ProcessWrite();
+}
+
+/** Called on a successful connect
+ */
+void ConnectionSocket::OnConnect()
+{
+}
+
+/** Called when a connection is not successful
+ * @param error The error
+ */
+void ConnectionSocket::OnError(const Anope::string &error)
+{
}
/** Constructor