mirror of
https://github.com/anope/anope.git
synced 2026-07-08 21:33:12 +02:00
Made Anope able to process normally when disconnected from the uplink and not sleep(), enable usage of non-blocking connect() and default all sockets to non blocking mode. Some cleanup to m_ssl and some cleanup to main.cpp.
This commit is contained in:
+11
-14
@@ -456,14 +456,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.
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
+6
-1
@@ -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();
|
||||
|
||||
+1
-3
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-14
@@ -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 ¶m);
|
||||
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 ****/
|
||||
|
||||
|
||||
+4
-8
@@ -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();
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
+43
-13
@@ -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 void Accept(ListenSocket *s);
|
||||
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 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
|
||||
|
||||
@@ -136,7 +136,7 @@ class DBMySQL : public Module
|
||||
if (operserv)
|
||||
this->AddCommand(operserv->Bot(), &commandsqlsync);
|
||||
|
||||
if (uplink_server)
|
||||
if (CurrentUplink)
|
||||
OnServerConnect();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+82
-70
@@ -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()
|
||||
|
||||
+23
-14
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -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},
|
||||
|
||||
+21
-2
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
+208
-278
@@ -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,22 +89,113 @@ 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());
|
||||
|
||||
/* 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());
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ircdproto->SendSquit(Config->ServerName, quitmsg);
|
||||
|
||||
this->ProcessWrite(); // Write out the last bit
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
UplinkSock = NULL;
|
||||
|
||||
if (!quitting)
|
||||
{
|
||||
int Retry = Config->RetryWait;
|
||||
if (Retry <= 0)
|
||||
Retry = 60;
|
||||
|
||||
Log() << "Retrying in " << Retry << " seconds";
|
||||
new ReconnectTimer(Retry);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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 Connect()
|
||||
{
|
||||
if (static_cast<unsigned>(++CurrentUplink) >= Config->Uplinks.size())
|
||||
CurrentUplink = 0;
|
||||
|
||||
Uplink *u = Config->Uplinks[CurrentUplink];
|
||||
|
||||
new UplinkSocket();
|
||||
if (!Config->LocalHost.empty())
|
||||
UplinkSock->Bind(Config->LocalHost);
|
||||
FOREACH_MOD(I_OnPreServerConnect, OnPreServerConnect());
|
||||
UplinkSock->Connect(u->host, u->port);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -124,95 +212,6 @@ void save_databases()
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Restarts services */
|
||||
void do_restart_services()
|
||||
{
|
||||
if (!readonly)
|
||||
{
|
||||
save_databases();
|
||||
}
|
||||
Log() << "Restarting";
|
||||
|
||||
if (quitmsg.empty())
|
||||
quitmsg = "Restarting";
|
||||
|
||||
FOREACH_MOD(I_OnRestart, OnRestart());
|
||||
ModuleManager::UnloadAll();
|
||||
|
||||
/* 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());
|
||||
}
|
||||
|
||||
ircdproto->SendSquit(Config->ServerName, quitmsg);
|
||||
delete UplinkSock;
|
||||
SocketEngine::Shutdown();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Terminates services */
|
||||
|
||||
static void services_shutdown()
|
||||
{
|
||||
if (quitmsg.empty())
|
||||
quitmsg = "Terminating, reason unknown";
|
||||
Log() << quitmsg;
|
||||
|
||||
FOREACH_MOD(I_OnShutdown, OnShutdown());
|
||||
ModuleManager::UnloadAll();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/* just in case they weren't all removed at least run once */
|
||||
ModuleManager::CleanupRuntimeDirectory();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* If we get a weird signal, come here. */
|
||||
|
||||
void sighandler(int signum)
|
||||
@@ -314,202 +313,133 @@ 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ircdproto->SendConnect();
|
||||
FOREACH_MOD(I_OnServerConnect, OnServerConnect());
|
||||
|
||||
started = true;
|
||||
|
||||
/* Set up timers */
|
||||
time_t last_check = Anope::CurTime;
|
||||
UpdateTimer updateTimer(Config->UpdateTimeout);
|
||||
|
||||
/*** Main loop. ***/
|
||||
while (!quitting)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (Anope::CurTime - last_check >= Config->TimeoutCheck)
|
||||
{
|
||||
TimerManager::TickTimers(Anope::CurTime);
|
||||
last_check = Anope::CurTime;
|
||||
}
|
||||
|
||||
/* Free up any finished threads */
|
||||
threadEngine.Process();
|
||||
|
||||
/* Process any modes that need to be (un)set */
|
||||
if (Me != NULL && Me->IsSynced())
|
||||
ModeManager::ProcessModes();
|
||||
|
||||
/* Process the socket engine */
|
||||
SocketEngine::Process();
|
||||
}
|
||||
|
||||
if (quitting)
|
||||
/* Disconnect and exit */
|
||||
services_shutdown();
|
||||
else
|
||||
{
|
||||
FOREACH_MOD(I_OnServerDisconnect, OnServerDisconnect());
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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 (!ex.GetReason().empty())
|
||||
Log(LOG_TERMINAL) << ex.GetReason();
|
||||
if (started)
|
||||
services_shutdown();
|
||||
Log() << ex.GetReason();
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
started = true;
|
||||
|
||||
/* 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";
|
||||
|
||||
if (Anope::CurTime - last_check >= Config->TimeoutCheck)
|
||||
{
|
||||
TimerManager::TickTimers(Anope::CurTime);
|
||||
last_check = Anope::CurTime;
|
||||
}
|
||||
|
||||
/* Free up any finished threads */
|
||||
threadEngine.Process();
|
||||
|
||||
/* Process any modes that need to be (un)set */
|
||||
if (Me->IsSynced())
|
||||
ModeManager::ProcessModes();
|
||||
|
||||
/* Process the socket engine */
|
||||
SocketEngine::Process();
|
||||
}
|
||||
|
||||
if (save_data)
|
||||
{
|
||||
ircdproto->SendGlobops(NULL, "Updating databases on shutdown, please wait.");
|
||||
save_databases();
|
||||
save_data = false;
|
||||
}
|
||||
|
||||
if (restarting)
|
||||
{
|
||||
FOREACH_MOD(I_OnRestart, OnRestart());
|
||||
}
|
||||
else
|
||||
{
|
||||
FOREACH_MOD(I_OnShutdown, OnShutdown());
|
||||
}
|
||||
|
||||
if (quitmsg.empty())
|
||||
quitmsg = "Terminating, reason unknown";
|
||||
Log() << quitmsg;
|
||||
|
||||
ModuleManager::UnloadAll();
|
||||
SocketEngine::Shutdown();
|
||||
for (Module *m; (m = ModuleManager::FindFirstOf(PROTOCOL)) != NULL;)
|
||||
ModuleManager::UnloadModule(m, NULL);
|
||||
|
||||
ModuleManager::CleanupRuntimeDirectory();
|
||||
|
||||
if (restarting)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ bool OnStats(const Anope::string &source, const std::vector<Anope::string> ¶
|
||||
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]);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
+98
-36
@@ -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->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());
|
||||
}
|
||||
|
||||
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());
|
||||
int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
|
||||
if (c == -1)
|
||||
{
|
||||
if (Anope::LastErrorCode() != EINPROGRESS)
|
||||
throw SocketException("Error connecting to server: " + Anope::LastError());
|
||||
else
|
||||
SocketEngine::MarkWritable(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->OnConnect();
|
||||
s->connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
this->IO->Connect(this, TargetHost, Port, BindHost);
|
||||
}
|
||||
catch (const SocketException &)
|
||||
{
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user