summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2010-10-01 21:01:49 -0400
committerAdam <Adam@anope.org>2010-10-01 21:01:49 -0400
commitd44f7971b129aa7ba80999f16f17b8c7499686e1 (patch)
treea86d08c3e641ed6b499b53b3bbb74e2a7f5b0dfb
parent70056dd4689eeab4f7a9b31a921e0d7e40d5ed0d (diff)
Rewrote some of the socket code to allow m_ssl to be a service.
This allows modules (xmlrpc) to create and accept SSL connections. Also fixed unloading m_mysql at certain times and made the threading engine always work correctly on Windows.
-rw-r--r--include/dns.h5
-rw-r--r--include/extern.h14
-rw-r--r--include/modules.h8
-rw-r--r--include/sockets.h260
-rw-r--r--include/threadengine.h7
-rw-r--r--modules/extra/db_mysql.cpp2
-rw-r--r--modules/extra/m_mysql.cpp8
-rw-r--r--modules/extra/m_ssl.cpp246
-rw-r--r--modules/extra/ssl.h9
-rw-r--r--modules/socketengines/m_socketengine_epoll.cpp8
-rw-r--r--modules/socketengines/m_socketengine_select.cpp26
-rwxr-xr-xsrc/bin/mydbgen1
-rw-r--r--src/dns.cpp15
-rw-r--r--src/mail.cpp4
-rw-r--r--src/main.cpp40
-rw-r--r--src/misc.cpp2
-rw-r--r--src/modules.cpp1
-rw-r--r--src/socketengines/socketengine_eventfd.cpp41
-rw-r--r--src/socketengines/socketengine_pipe.cpp3
-rw-r--r--src/socketengines/socketengine_win32.cpp7
-rw-r--r--src/sockets.cpp324
-rw-r--r--src/threadengine.cpp23
-rw-r--r--src/threadengines/threadengine_pthread.cpp8
-rw-r--r--src/threadengines/threadengine_win32.cpp6
-rw-r--r--src/users.cpp1
25 files changed, 721 insertions, 348 deletions
diff --git a/include/dns.h b/include/dns.h
index 8a7d7a4a2..7bfdac59a 100644
--- a/include/dns.h
+++ b/include/dns.h
@@ -126,13 +126,14 @@ struct DNSRecord
/** The socket used to talk to the nameserver, uses UDP
*/
-class DNSSocket : public ClientSocket
+class DNSSocket : public ConnectionSocket
{
private:
int SendTo(const unsigned char *buf, size_t len) const;
int RecvFrom(char *buf, size_t size, sockaddrs &addrs) const;
+
public:
- DNSSocket(const Anope::string &nTargetHost, int Port);
+ DNSSocket();
virtual ~DNSSocket();
bool ProcessRead();
diff --git a/include/extern.h b/include/extern.h
index 249ac6dfb..12fbcbbc5 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -183,13 +183,24 @@ E Anope::string quitmsg;
E bool save_data;
E time_t start_time;
-E Socket *UplinkSock;
+E ConnectionSocket *UplinkSock;
E void save_databases();
E void expire_all();
E void sighandler(int signum);
E void do_restart_services();
+/* The socket to our uplink */
+class UplinkSocket : public ConnectionSocket
+{
+ public:
+ UplinkSocket(bool ipv6 = false);
+
+ virtual ~UplinkSocket();
+
+ bool Read(const Anope::string &buf);
+};
+
/**** memory.c ****/
E void *scalloc(long elsize, long els);
@@ -334,6 +345,7 @@ E int exception_add(User *u, const Anope::string &mask, int limit, const Anope::
E SocketEngineBase *SocketEngine;
E int32 TotalRead;
E int32 TotalWritten;
+E SocketIO normalSocketIO;
/**** users.c ****/
diff --git a/include/modules.h b/include/modules.h
index 53cd81340..ab3472132 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -1236,11 +1236,10 @@ class Service : public virtual Base
template<typename T>
class service_reference : public dynamic_reference<T>
{
- Module *owner;
Anope::string name;
public:
- service_reference(Module *o, const Anope::string &n) : dynamic_reference<T>(static_cast<T *>(ModuleManager::GetService(this->name))), owner(o), name(n)
+ service_reference(const Anope::string &n) : dynamic_reference<T>(static_cast<T *>(ModuleManager::GetService(n))), name(n)
{
}
@@ -1263,11 +1262,6 @@ class service_reference : public dynamic_reference<T>
}
return this->ref;
}
-
- inline T *operator->()
- {
- return this->ref;
- }
};
struct Message
diff --git a/include/sockets.h b/include/sockets.h
index 38060ed78..847e91309 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -30,6 +30,14 @@ union CoreExport sockaddrs
sockaddr_in sa4;
sockaddr_in6 sa6;
+ /** Construct the object, sets everything to 0
+ */
+ sockaddrs();
+
+ /** Memset the object to 0
+ */
+ void clear();
+
/** Get the size of the sockaddr we represent
* @return The size
*/
@@ -45,10 +53,6 @@ union CoreExport sockaddrs
*/
Anope::string addr() const;
- /** Construct the object, sets everything to 0
- */
- sockaddrs();
-
/** Check if this sockaddr has data in it
*/
bool operator()() const;
@@ -92,6 +96,9 @@ class SocketException : public CoreException
enum SocketType
{
+ SOCKTYPE_BASE,
+ SOCKTYPE_BUFFERED,
+ SOCKTYPE_CONNECTION,
SOCKTYPE_CLIENT,
SOCKTYPE_LISTEN
};
@@ -102,34 +109,59 @@ enum SocketFlag
SF_WRITABLE
};
-class CoreExport Socket : public Flags<SocketFlag, 2>
+class Socket;
+class ClientSocket;
+class ListenSocket;
+class ConnectionSocket;
+
+class SocketIO
{
- protected:
- /** Really receive something from the buffer
+ public:
+ /** Receive something from the buffer
+ * @param s The socket
* @param buf The buf to read to
* @param sz How much to read
* @return Number of bytes received
*/
- virtual int RecvInternal(char *buf, size_t sz) const;
+ virtual int Recv(Socket *s, char *buf, size_t sz) const;
- /** Really write something to the socket
+ /** Write something to the socket
+ * @param s The socket
* @param buf What to write
* @return Number of bytes written
*/
- virtual int SendInternal(const Anope::string &buf) const;
+ virtual int Send(Socket *s, const Anope::string &buf) const;
+
+ /** Accept a connection from a socket
+ * @param s The socket
+ */
+ virtual void 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
+ */
+ virtual void Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip = "");
+ /** Called when the socket is destructing
+ */
+ virtual void Destroy() { }
+};
+
+class CoreExport Socket : public Flags<SocketFlag, 2>, public virtual Base
+{
+ protected:
/* Socket FD */
int Sock;
/* Is this an IPv6 socket? */
bool IPv6;
- /* Things to be written to the socket */
- std::string WriteBuffer;
- /* Part of a message sent from the server, but not totally received */
- std::string extrabuf;
- /* How much data was received from this socket */
- size_t RecvLen;
public:
+ /* I/O functions used for this socket */
+ SocketIO *IO;
+
/* Type this socket is */
SocketType Type;
@@ -138,11 +170,11 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
Socket();
/** Default constructor
- * @param nsock The socket to use, 0 if we need to create our own
- * @param nIPv6 true if using ipv6
+ * @param sock The socket to use, 0 if we need to create our own
+ * @param ipv6 true if using ipv6
* @param type The socket type, defaults to SOCK_STREAM
*/
- Socket(int nsock, bool nIPv6, int type = SOCK_STREAM);
+ Socket(int sock, bool ipv6, int type = SOCK_STREAM);
/** Default destructor
*/
@@ -151,7 +183,12 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
/** Get the socket FD for this socket
* @return the fd
*/
- int GetSock() const;
+ int GetFD() const;
+
+ /** Check if this socket is IPv6
+ * @return true or false
+ */
+ bool IsIPv6() const;
/** Mark a socket as blockig
* @return true if the socket is now blocking
@@ -163,21 +200,6 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
*/
bool SetNonBlocking();
- /** Check if this socket is IPv6
- * @return true or false
- */
- bool IsIPv6() const;
-
- /** Get the length of the read buffer
- * @return The length of the read buffer
- */
- size_t ReadBufferLen() const;
-
- /** Get the length of the write buffer
- * @return The length of the write buffer
- */
- size_t WriteBufferLen() const;
-
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
@@ -192,6 +214,43 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
* @return true on success, false to drop this socket
*/
virtual void ProcessError();
+};
+
+class CoreExport BufferedSocket : public Socket
+{
+ protected:
+ /* Things to be written to the socket */
+ std::string WriteBuffer;
+ /* Part of a message sent from the server, but not totally received */
+ std::string extrabuf;
+ /* How much data was received from this socket */
+ size_t RecvLen;
+
+ public:
+ /** Blank constructor
+ */
+ BufferedSocket();
+
+ /** Constructor
+ * @param fd FD to use
+ * @param ipv6 true for ipv6
+ * @param type socket type, defaults to SOCK_STREAM
+ */
+ BufferedSocket(int fd, bool ipv6, int type = SOCK_STREAM);
+
+ /** Default destructor
+ */
+ virtual ~BufferedSocket();
+
+ /** Called when there is something to be received for this socket
+ * @return true on success, false to drop this socket
+ */
+ bool ProcessRead();
+
+ /** Called when the socket is ready to be written to
+ * @return true on success, false to drop this socket
+ */
+ bool ProcessWrite();
/** Called with a line received from the socket
* @param buf The line
@@ -200,106 +259,119 @@ class CoreExport Socket : public Flags<SocketFlag, 2>
virtual bool Read(const Anope::string &buf);
/** Write to the socket
- * @param message The message
- */
+ * @param message The message
+ */
void Write(const char *message, ...);
void Write(const Anope::string &message);
-};
-class CoreExport Pipe : public Socket
-{
- private:
- /** The FD of the write pipe (if this isn't evenfd)
- * this->Sock is the readfd
+ /** Get the length of the read buffer
+ * @return The length of the read buffer
*/
- int WritePipe;
+ size_t ReadBufferLen() const;
- /** Our overloaded RecvInternal call
+ /** Get the length of the write buffer
+ * @return The length of the write buffer
*/
- int RecvInternal(char *buf, size_t sz) const;
+ size_t WriteBufferLen() const;
+};
- /** Our overloaded SendInternal call
- */
- int SendInternal(const Anope::string &buf) const;
- public:
- /** Constructor
- */
- Pipe();
+class CoreExport ListenSocket : public Socket
+{
+ protected:
+ /* Sockaddrs for bindip/port */
+ sockaddrs listenaddrs;
- /** Called when data is to be read
+ public:
+ /** Constructor
+ * @param bindip The IP to bind to
+ * @param port The port to listen on
+ * @param ipv6 true for ipv6
*/
- bool ProcessRead();
+ ListenSocket(const Anope::string &bindip, int port, bool ipv6);
- /** Function that calls OnNotify
+ /** Destructor
*/
- bool Read(const Anope::string &);
+ virtual ~ListenSocket();
- /** Called when this pipe needs to be woken up
+ /** Process what has come in from the connection
+ * @return false to destory this socket
*/
- void Notify();
+ bool ProcessRead();
- /** Should be overloaded to do something useful
+ /** Called when a connection is accepted
+ * @param fd The FD for the new connection
+ * @param addr The sockaddr for where the connection came from
+ * @return The new socket
*/
- virtual void OnNotify();
+ virtual ClientSocket *OnAccept(int fd, const sockaddrs &addr);
};
-class CoreExport ClientSocket : public Socket
+class ConnectionSocket : public BufferedSocket
{
- protected:
+ public:
/* Sockaddrs for bindip (if there is one) */
- sockaddrs bindaddrs;
+ sockaddrs bindaddr;
/* Sockaddrs for connection ip/port */
- sockaddrs conaddrs;
-
- public:
+ sockaddrs conaddr;
/** Constructor
+ * @param ipv6 true to use IPv6
+ * @param type The socket type, defaults to SOCK_STREAM
+ */
+ ConnectionSocket(bool ipv6 = false, int type = SOCK_STREAM);
+
+ /** 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
- * @param nIPv6 true to use IPv6
- * @param type The socket type, defaults to SOCK_STREAM
*/
- ClientSocket(const Anope::string &TargetHost, int Port, const Anope::string &BindHost = "", bool nIPv6 = false, int type = SOCK_STREAM);
+ void Connect(const Anope::string &TargetHost, int Port, const Anope::string &BindHost = "");
+};
- /** Default destructor
- */
- virtual ~ClientSocket();
+class ClientSocket : public BufferedSocket
+{
+ /* Listen socket this connection came from */
+ ListenSocket *LS;
+ /* Clients address */
+ sockaddrs clientaddr;
+ public:
- /** Called with a line received from the socket
- * @param buf The line
- * @return true to continue reading, false to drop the socket
+ /** Constructor
+ * @param ls Listen socket this connection is from
+ * @param fd New FD for this socket
+ * @param addr Address the connection came from
*/
- virtual bool Read(const Anope::string &buf);
+ ClientSocket(ListenSocket *ls, int fd, const sockaddrs &addr);
};
-class CoreExport ListenSocket : public Socket
+class CoreExport Pipe : public BufferedSocket
{
- protected:
- /* Sockaddrs for bindip/port */
- sockaddrs listenaddrs;
+ private:
+ /** The FD of the write pipe (if this isn't evenfd)
+ * this->Sock is the readfd
+ */
+ int WritePipe;
public:
- /** Constructor
- * @param bindip The IP to bind to
- * @param port The port to listen on
+ /** Constructor
*/
- ListenSocket(const Anope::string &bindip, int port);
+ Pipe();
- /** Destructor
+ /** Called when data is to be read
*/
- virtual ~ListenSocket();
+ bool ProcessRead();
- /** Process what has come in from the connection
- * @return false to destory this socket
+ /** Function that calls OnNotify
*/
- bool ProcessRead();
+ bool Read(const Anope::string &);
- /** Called when a connection is accepted
- * @param s The socket for the new connection
- * @return true if the listen socket should remain alive
+ /** Called when this pipe needs to be woken up
*/
- virtual bool OnAccept(Socket *s);
+ void Notify();
+
+ /** Should be overloaded to do something useful
+ */
+ virtual void OnNotify();
};
#endif // SOCKET_H
diff --git a/include/threadengine.h b/include/threadengine.h
index 1337f0c61..764c26242 100644
--- a/include/threadengine.h
+++ b/include/threadengine.h
@@ -20,6 +20,9 @@ extern CoreExport ThreadEngine threadEngine;
class ThreadEngine
{
public:
+ /* Vector of threads */
+ std::vector<Thread *> threads;
+
/** Threadengines constructor
*/
ThreadEngine();
@@ -32,6 +35,10 @@ class ThreadEngine
* @param thread A pointer to a newley allocated thread
*/
void Start(Thread *thread);
+
+ /** Check for finished threads
+ */
+ void Process();
};
class Thread : public Extensible
diff --git a/modules/extra/db_mysql.cpp b/modules/extra/db_mysql.cpp
index b15ce4de4..274f653b2 100644
--- a/modules/extra/db_mysql.cpp
+++ b/modules/extra/db_mysql.cpp
@@ -352,7 +352,7 @@ class DBMySQL : public Module
return SQL ? SQL->Escape(query) : query;
}
- DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), interface(this), SQL(this, "mysql/main")
+ DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), interface(this), SQL("mysql/main")
{
me = this;
diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp
index f641aa655..de855cead 100644
--- a/modules/extra/m_mysql.cpp
+++ b/modules/extra/m_mysql.cpp
@@ -186,6 +186,7 @@ class ModuleSQL : public Module
DThread->SetExitState();
DThread->Wakeup();
DThread->Join();
+ delete DThread;
delete SQLPipe;
}
@@ -234,6 +235,7 @@ class ModuleSQL : public Module
{
MySQLService *ss = new MySQLService(this, connname, database, server, user, password, port);
this->MySQLServices.insert(std::make_pair(connname, ss));
+ ModuleManager::RegisterService(ss);
Log(LOG_NORMAL, "mysql") << "MySQL: Sucessfully connected to server " << connname << " (" << server << ")";
}
@@ -284,13 +286,13 @@ MySQLService::~MySQLService()
for (unsigned i = me->QueryRequests.size(); i > 0; --i)
{
- QueryRequest &r = me->QueryRequests[i];
+ QueryRequest &r = me->QueryRequests[i - 1];
if (r.service == this)
{
if (r.interface)
r.interface->OnError(SQLResult("", "SQL Interface is going away"));
- me->QueryRequests.erase(me->QueryRequests.begin() + i);
+ me->QueryRequests.erase(me->QueryRequests.begin() + i - 1);
}
}
this->Lock.Unlock();
@@ -373,7 +375,7 @@ void DispatcherThread::Run()
r.service->Lock.Unlock();
this->Lock();
- if (me->QueryRequests.front().query == r.query)
+ if (!me->QueryRequests.empty() && me->QueryRequests.front().query == r.query)
{
if (r.interface)
me->FinishedRequests.push_back(QueryResult(r.interface, sresult));
diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl.cpp
index 5e081c193..9fefb942a 100644
--- a/modules/extra/m_ssl.cpp
+++ b/modules/extra/m_ssl.cpp
@@ -1,6 +1,7 @@
/* RequiredLibraries: ssl,crypt */
#include "module.h"
+#include "ssl.h"
#define OPENSSL_NO_SHA512
#include <openssl/bio.h>
@@ -12,74 +13,98 @@
#define CERTFILE "anope.cert"
#define KEYFILE "anope.key"
-static SSL_CTX *ctx;
+static SSL_CTX *server_ctx, *client_ctx;
-class SSLSocket : public ClientSocket
+class MySSLService : public SSLService
{
- private:
- SSL *sslsock;
-
- int RecvInternal(char *buf, size_t sz) const
- {
- return SSL_read(sslsock, buf, sz);
- }
-
- int SendInternal(const Anope::string &buf) const
- {
- return SSL_write(sslsock, buf.c_str(), buf.length());
- }
public:
- SSLSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost = "", bool nIPv6 = false) : ClientSocket(nTargetHost, nPort, nBindHost, nIPv6)
- {
- this->SetBlocking();
+ MySSLService(Module *o, const Anope::string &n);
- sslsock = SSL_new(ctx);
+ /** Initialize a socket to use SSL
+ * @param s The socket
+ */
+ void Init(Socket *s);
+};
- if (!sslsock)
- throw CoreException("Unable to initialize SSL socket");
+class SSLSocketIO : public SocketIO
+{
+ public:
+ /* The SSL socket for this socket */
+ SSL *sslsock;
- SSL_set_connect_state(sslsock);
- SSL_set_fd(sslsock, Sock);
- SSL_connect(sslsock);
+ /** Constructor
+ */
+ SSLSocketIO();
- UplinkSock = this;
+ /** Really receive something from the buffer
+ * @param s The socket
+ * @param buf The buf to read to
+ * @param sz How much to read
+ * @return Number of bytes received
+ */
+ int Recv(Socket *s, char *buf, size_t sz) const;
- this->SetNonBlocking();
- }
+ /** 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;
- ~SSLSocket()
- {
- SSL_shutdown(sslsock);
- SSL_free(sslsock);
+ /** Accept a connection from a socket
+ * @param s The socket
+ */
+ void Accept(ListenSocket *s);
- UplinkSock = NULL;
- }
+ /** 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 = "");
- bool Read(const Anope::string &buf)
- {
- process(buf);
- return true;
- }
+ /** Called when the socket is destructing
+ */
+ void Destroy();
};
+class SSLModule;
+static SSLModule *me;
class SSLModule : public Module
{
+ static int AlwaysAccept(int, X509_STORE_CTX *)
+ {
+ return 1;
+ }
+
public:
- SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator)
+ MySSLService service;
+
+ SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), service(this, "ssl")
{
+ me = this;
+
+ this->SetAuthor("Anope");
+ this->SetType(SUPPORTED);
+ this->SetPermanent(true);
+
+ SSL_library_init();
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
- ctx = SSL_CTX_new(SSLv23_client_method());
+ client_ctx = SSL_CTX_new(SSLv23_client_method());
+ server_ctx = SSL_CTX_new(SSLv23_server_method());
- if (!ctx)
+ if (!client_ctx || !server_ctx)
throw ModuleException("Error initializing SSL CTX");
if (IsFile(CERTFILE))
{
- if (!SSL_CTX_use_certificate_file(ctx, CERTFILE, SSL_FILETYPE_PEM))
+ if (!SSL_CTX_use_certificate_file(client_ctx, CERTFILE, SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_file(server_ctx, CERTFILE, SSL_FILETYPE_PEM))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading certificate");
}
}
@@ -88,9 +113,10 @@ class SSLModule : public Module
if (IsFile(KEYFILE))
{
- if (!SSL_CTX_use_PrivateKey_file(ctx, KEYFILE, SSL_FILETYPE_PEM))
+ if (!SSL_CTX_use_PrivateKey_file(client_ctx, KEYFILE, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, KEYFILE, SSL_FILETYPE_PEM))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading private key");
}
}
@@ -98,26 +124,29 @@ class SSLModule : public Module
{
if (IsFile(CERTFILE))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading private key - file not found");
}
else
Log() << "m_ssl: No private key found";
}
- this->SetAuthor("Anope");
- this->SetType(SUPPORTED);
- this->SetPermanent(true);
+ SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
- SSL_CTX_set_options(ctx, SSL_OP_TLS_ROLLBACK_BUG | SSL_OP_ALL);
+ SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
+ SSL_CTX_set_verify(server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
+
+ ModuleManager::RegisterService(&this->service);
ModuleManager::Attach(I_OnPreServerConnect, this);
}
~SSLModule()
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
}
EventReturn OnPreServerConnect(Uplink *u, int Number)
@@ -128,19 +157,126 @@ class SSLModule : public Module
{
try
{
- new SSLSocket(u->host, u->port, Config->LocalHost, u->ipv6);
- Log() << "Connected to Server " << Number << " (" << u->host << ":" << u->port << ")";
+ new UplinkSocket(uplink_server->ipv6);
+ this->service.Init(UplinkSock);
+ UplinkSock->Connect(uplink_server->host, 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();
+ Log() << "Unable to connect with SSL to server " << Number << " (" << u->host << ":" << u->port << "), " << ex.GetReason();
}
- return EVENT_ALLOW;
+ return EVENT_STOP;
}
return EVENT_CONTINUE;
}
};
+MySSLService::MySSLService(Module *o, const Anope::string &n) : SSLService(o, n)
+{
+}
+
+void MySSLService::Init(Socket *s)
+{
+ if (s->IO != &normalSocketIO)
+ throw CoreException("Socket initializing SSL twice");
+
+ s->IO = new SSLSocketIO();
+}
+
+SSLSocketIO::SSLSocketIO()
+{
+ this->sslsock = NULL;
+}
+
+int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz) const
+{
+ size_t i = SSL_read(this->sslsock, buf, sz);
+ TotalRead += i;
+ return i;
+}
+
+int SSLSocketIO::Send(Socket *s, const Anope::string &buf) const
+{
+ size_t i = SSL_write(this->sslsock, buf.c_str(), buf.length());
+ TotalWritten += i;
+ return i;
+}
+
+void 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);
+ me->service.Init(newsocket);
+ SSLSocketIO *IO = debug_cast<SSLSocketIO *>(newsocket->IO);
+
+ IO->sslsock = SSL_new(server_ctx);
+ if (!IO->sslsock)
+ throw SocketException("Unable to initialize SSL socket");
+
+ SSL_set_accept_state(IO->sslsock);
+
+ if (!SSL_set_fd(IO->sslsock, newsock))
+ 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)));
+ }
+}
+
+void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &TargetHost, int Port, const Anope::string &BindHost)
+{
+ if (s->IO == &normalSocketIO)
+ throw SocketException("Attempting to connect uninitialized socket with SQL");
+
+ normalSocketIO.Connect(s, TargetHost, Port, BindHost);
+
+ SSLSocketIO *IO = debug_cast<SSLSocketIO *>(s->IO);
+
+ IO->sslsock = SSL_new(client_ctx);
+ if (!IO->sslsock)
+ throw SocketException("Unable to initialize SSL socket");
+
+ 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)));
+ }
+}
+
+void SSLSocketIO::Destroy()
+{
+ if (this->sslsock)
+ {
+ SSL_shutdown(this->sslsock);
+ SSL_free(this->sslsock);
+ }
+}
+
MODULE_INIT(SSLModule)
diff --git a/modules/extra/ssl.h b/modules/extra/ssl.h
new file mode 100644
index 000000000..e25251379
--- /dev/null
+++ b/modules/extra/ssl.h
@@ -0,0 +1,9 @@
+
+class SSLService : public Service
+{
+ public:
+ SSLService(Module *o, const Anope::string &n) : Service(o, n) { }
+
+ virtual void Init(Socket *s) = 0;
+};
+
diff --git a/modules/socketengines/m_socketengine_epoll.cpp b/modules/socketengines/m_socketengine_epoll.cpp
index 7b8dbdde5..713c1f0ff 100644
--- a/modules/socketengines/m_socketengine_epoll.cpp
+++ b/modules/socketengines/m_socketengine_epoll.cpp
@@ -48,7 +48,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
{
@@ -67,7 +67,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_DEL, ev.data.fd, &ev) == -1)
{
@@ -90,7 +90,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN | EPOLLOUT;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as writable in socketengine epoll: " << Anope::LastError();
@@ -108,7 +108,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as unwritable in socketengine epoll: " << Anope::LastError();
diff --git a/modules/socketengines/m_socketengine_select.cpp b/modules/socketengines/m_socketengine_select.cpp
index 733547167..b1c1c065f 100644
--- a/modules/socketengines/m_socketengine_select.cpp
+++ b/modules/socketengines/m_socketengine_select.cpp
@@ -26,26 +26,26 @@ class SocketEngineSelect : public SocketEngineBase
void AddSocket(Socket *s)
{
- if (s->GetSock() > MaxFD)
- MaxFD = s->GetSock();
- FD_SET(s->GetSock(), &ReadFDs);
- Sockets.insert(std::make_pair(s->GetSock(), s));
+ if (s->GetFD() > MaxFD)
+ MaxFD = s->GetFD();
+ FD_SET(s->GetFD(), &ReadFDs);
+ Sockets.insert(std::make_pair(s->GetFD(), s));
}
void DelSocket(Socket *s)
{
- if (s->GetSock() == MaxFD)
+ if (s->GetFD() == MaxFD)
--MaxFD;
- FD_CLR(s->GetSock(), &ReadFDs);
- FD_CLR(s->GetSock(), &WriteFDs);
- Sockets.erase(s->GetSock());
+ FD_CLR(s->GetFD(), &ReadFDs);
+ FD_CLR(s->GetFD(), &WriteFDs);
+ Sockets.erase(s->GetFD());
}
void MarkWritable(Socket *s)
{
if (s->HasFlag(SF_WRITABLE))
return;
- FD_SET(s->GetSock(), &WriteFDs);
+ FD_SET(s->GetFD(), &WriteFDs);
s->SetFlag(SF_WRITABLE);
}
@@ -53,7 +53,7 @@ class SocketEngineSelect : public SocketEngineBase
{
if (!s->HasFlag(SF_WRITABLE))
return;
- FD_CLR(s->GetSock(), &WriteFDs);
+ FD_CLR(s->GetFD(), &WriteFDs);
s->UnsetFlag(SF_WRITABLE);
}
@@ -79,15 +79,15 @@ class SocketEngineSelect : public SocketEngineBase
if (s->HasFlag(SF_DEAD))
continue;
- if (FD_ISSET(s->GetSock(), &efdset))
+ if (FD_ISSET(s->GetFD(), &efdset))
{
s->ProcessError();
s->SetFlag(SF_DEAD);
continue;
}
- if (FD_ISSET(s->GetSock(), &rfdset) && !s->ProcessRead())
+ if (FD_ISSET(s->GetFD(), &rfdset) && !s->ProcessRead())
s->SetFlag(SF_DEAD);
- if (FD_ISSET(s->GetSock(), &wfdset) && !s->ProcessWrite())
+ if (FD_ISSET(s->GetFD(), &wfdset) && !s->ProcessWrite())
s->SetFlag(SF_DEAD);
}
diff --git a/src/bin/mydbgen b/src/bin/mydbgen
index f5663ab61..7e3d1929b 100755
--- a/src/bin/mydbgen
+++ b/src/bin/mydbgen
@@ -147,7 +147,6 @@ if test "x$FAILED" = "x" ; then
echo " username = \"$SQLUSER\""
echo " password = \"$SQLPASS\""
echo " port = \"$SQLPORT\""
- echo " updatedelay = \"60\""
echo "}"
echo ""
else
diff --git a/src/dns.cpp b/src/dns.cpp
index 30624aeca..9f99a5b49 100644
--- a/src/dns.cpp
+++ b/src/dns.cpp
@@ -12,7 +12,10 @@ DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache, Modu
if (!DNSEngine)
DNSEngine = new DNSManager();
if (!DNSEngine->sock)
- DNSEngine->sock = new DNSSocket(Config->NameServer, DNSManager::DNSPort);
+ {
+ DNSEngine->sock = new DNSSocket();
+ DNSEngine->sock->Connect(Config->NameServer, DNSManager::DNSPort);
+ }
if (DNSEngine->packets.size() == 65535)
throw SocketException("DNS queue full");
@@ -197,7 +200,7 @@ inline DNSRecord::DNSRecord()
this->created = Anope::CurTime;
}
-DNSSocket::DNSSocket(const Anope::string &TargetHost, int Port) : ClientSocket(TargetHost, Port, "", false, SOCK_DGRAM)
+DNSSocket::DNSSocket() : ConnectionSocket(false, SOCK_DGRAM)
{
}
@@ -209,13 +212,13 @@ DNSSocket::~DNSSocket()
int DNSSocket::SendTo(const unsigned char *buf, size_t len) const
{
- return sendto(this->GetSock(), buf, len, 0, &this->conaddrs.sa, this->conaddrs.size());
+ return sendto(this->GetFD(), buf, len, 0, &this->conaddr.sa, this->conaddr.size());
}
int DNSSocket::RecvFrom(char *buf, size_t len, sockaddrs &addrs) const
{
socklen_t x = sizeof(addrs);
- return recvfrom(this->GetSock(), buf, len, 0, &addrs.sa, &x);
+ return recvfrom(this->GetFD(), buf, len, 0, &addrs.sa, &x);
}
bool DNSSocket::ProcessRead()
@@ -229,9 +232,9 @@ bool DNSSocket::ProcessRead()
if (length < 0)
return false;
- if (this->conaddrs != from_server)
+ if (this->conaddr != from_server)
{
- Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->conaddrs.addr() << "' != '" << from_server.addr() << "'";
+ Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->conaddr.addr() << "' != '" << from_server.addr() << "'";
return true;
}
diff --git a/src/mail.cpp b/src/mail.cpp
index 5cb64f6d3..66cf1b81e 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -13,7 +13,10 @@ void MailThread::Run()
FILE *pipe = popen(Config->SendMailPath.c_str(), "w");
if (!pipe)
+ {
+ SetExitState();
return;
+ }
fprintf(pipe, "From: %s\n", Config->SendFrom.c_str());
if (Config->DontQuoteAddresses)
@@ -27,6 +30,7 @@ void MailThread::Run()
pclose(pipe);
Success = true;
+ SetExitState();
}
bool Mail(User *u, NickRequest *nr, BotInfo *service, const Anope::string &subject, const Anope::string &message)
diff --git a/src/main.cpp b/src/main.cpp
index a1417b197..2f37b64d8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -104,27 +104,23 @@ class UpdateTimer : public Timer
}
};
-Socket *UplinkSock = NULL;
+ConnectionSocket *UplinkSock = NULL;
-class UplinkSocket : public ClientSocket
+UplinkSocket::UplinkSocket(bool ipv6) : ConnectionSocket(ipv6)
{
- public:
- UplinkSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost = "", bool nIPv6 = false) : ClientSocket(nTargetHost, nPort, nBindHost, nIPv6)
- {
- UplinkSock = this;
- }
+ UplinkSock = this;
+}
- ~UplinkSocket()
- {
- UplinkSock = NULL;
- }
+UplinkSocket::~UplinkSocket()
+{
+ UplinkSock = NULL;
+}
- bool Read(const Anope::string &buf)
- {
- process(buf);
- return true;
- }
-};
+bool UplinkSocket::Read(const Anope::string &buf)
+{
+ process(buf);
+ return true;
+}
/*************************************************************************/
@@ -354,13 +350,14 @@ static bool Connect()
if (MOD_RESULT != EVENT_CONTINUE)
{
if (MOD_RESULT == EVENT_STOP)
- break;
+ continue;
return true;
}
try
{
- new UplinkSocket(uplink_server->host, uplink_server->port, Config->LocalHost, uplink_server->ipv6);
+ new UplinkSocket(uplink_server->ipv6);
+ UplinkSock->Connect(uplink_server->host, uplink_server->port, Config->LocalHost);
}
catch (const SocketException &ex)
{
@@ -368,7 +365,7 @@ static bool Connect()
continue;
}
- Log() << "Connected to Server " << servernum << " (" << uplink_server->host << ":" << uplink_server->port << ")";
+ Log() << "Connected to server " << servernum << " (" << uplink_server->host << ":" << uplink_server->port << ")";
return true;
}
@@ -469,6 +466,9 @@ int main(int ac, char **av, char **envp)
last_check = Anope::CurTime;
}
+ /* Free up any finished threads */
+ threadEngine.Process();
+
/* Process any modes that need to be (un)set */
ModeManager::ProcessModes();
diff --git a/src/misc.cpp b/src/misc.cpp
index a835c8e41..72e991249 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -1317,7 +1317,7 @@ void Anope::Unhex(const Anope::string &src, char *dest)
const Anope::string Anope::LastError()
{
#ifndef _WIN32
- return LastError();
+ return strerror(errno);
#else
char errbuf[513];
DWORD err = GetLastError();
diff --git a/src/modules.cpp b/src/modules.cpp
index 127620333..a31a94786 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -332,7 +332,6 @@ void Module::SendMessage(BotInfo *from, User *to, const char *fmt, ...)
Service::Service(Module *o, const Anope::string &n) : owner(o), name(n)
{
- ModuleManager::RegisterService(this);
}
Service::~Service()
diff --git a/src/socketengines/socketengine_eventfd.cpp b/src/socketengines/socketengine_eventfd.cpp
index a0efe5286..4e4016326 100644
--- a/src/socketengines/socketengine_eventfd.cpp
+++ b/src/socketengines/socketengine_eventfd.cpp
@@ -1,32 +1,47 @@
#include "services.h"
#include <sys/eventfd.h>
-int Pipe::RecvInternal(char *buf, size_t sz) const
+class PipeIO : public SocketIO
{
- static eventfd_t dummy;
- return !eventfd_read(this->Sock, &dummy);
-}
-
-int Pipe::SendInternal(const Anope::string &) const
-{
- return !eventfd_write(this->Sock, 1);
-}
-
-Pipe::Pipe() : Socket()
+ public:
+ /** Receive something from the buffer
+ * @param s The socket
+ * @param buf The buf to read to
+ * @param sz How much to read
+ * @return Number of bytes received
+ */
+ int Recv(Socket *s, char *buf, size_t sz) const
+ {
+ static eventfd_t dummy;
+ return !eventfd_read(s->GetFD(), &dummy);
+ }
+
+ /** 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
+ {
+ return !eventfd_write(s->GetFD(), 1);
+ }
+} pipeSocketIO;
+
+Pipe::Pipe() : BufferedSocket()
{
+ this->IO = &pipeSocketIO;
this->Sock = eventfd(0, EFD_NONBLOCK);
if (this->Sock < 0)
throw CoreException(Anope::string("Could not create pipe: ") + Anope::LastError());
this->IPv6 = false;
- this->Type = SOCKTYPE_CLIENT;
SocketEngine->AddSocket(this);
}
bool Pipe::ProcessRead()
{
- this->RecvInternal(NULL, 0);
+ this->IO->Recv(this, NULL, 0);
return this->Read("");
}
diff --git a/src/socketengines/socketengine_pipe.cpp b/src/socketengines/socketengine_pipe.cpp
index b0be664c8..21a558d66 100644
--- a/src/socketengines/socketengine_pipe.cpp
+++ b/src/socketengines/socketengine_pipe.cpp
@@ -13,7 +13,7 @@ int Pipe::SendInternal(const Anope::string &) const
return write(this->WritePipe, &dummy, 1);
}
-Pipe::Pipe() : Socket()
+Pipe::Pipe() : BufferedSocket()
{
int fds[2];
if (pipe(fds))
@@ -26,7 +26,6 @@ Pipe::Pipe() : Socket()
this->Sock = fds[0];
this->WritePipe = fds[1];
this->IPv6 = false;
- this->Type = SOCKTYPE_CLIENT;
SocketEngine->AddSocket(this);
}
diff --git a/src/socketengines/socketengine_win32.cpp b/src/socketengines/socketengine_win32.cpp
index 1b1a4e50d..5d2c2d7cb 100644
--- a/src/socketengines/socketengine_win32.cpp
+++ b/src/socketengines/socketengine_win32.cpp
@@ -7,9 +7,9 @@ class LSocket : public ListenSocket
public:
LSocket(const Anope::string &host, int port) : ListenSocket(host, port) { }
- bool OnAccept(Socket *s)
+ bool OnAccept(int fd, const sockaddrs &)
{
- newsocket = s;
+ newsocket = new Socket(fd, this->IPv6);
return true;
}
};
@@ -26,7 +26,7 @@ int Pipe::SendInternal(const Anope::string &) const
return write(this->WritePipe, &dummy, 1);
}
-Pipe::Pipe() : Socket()
+Pipe::Pipe() : BufferedSocket()
{
LSocket lfs("127.0.0.1", 0);
@@ -47,7 +47,6 @@ Pipe::Pipe() : Socket()
this->Sock = cfd;
this->WritePipe = newsocket->GetSock();
this->IPv6 = false;
- this->Type = SOCKTYPE_CLIENT;
SocketEngine->AddSocket(this);
newsocket = NULL;
diff --git a/src/sockets.cpp b/src/sockets.cpp
index fe712357a..f22238fcc 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -4,6 +4,8 @@ SocketEngineBase *SocketEngine = NULL;
int32 TotalRead = 0;
int32 TotalWritten = 0;
+SocketIO normalSocketIO;
+
/** Trims all the \r and \ns from the begining and end of a string
* @param buffer The buffer to trim
*/
@@ -15,6 +17,20 @@ static void TrimBuf(std::string &buffer)
buffer.erase(buffer.length() - 1);
}
+/** Construct the object, sets everything to 0
+ */
+sockaddrs::sockaddrs()
+{
+ this->clear();
+}
+
+/** Memset the object to 0
+ */
+void sockaddrs::clear()
+{
+ memset(this, 0, sizeof(*this));
+}
+
/** Get the size of the sockaddr we represent
* @return The size
*/
@@ -75,13 +91,6 @@ Anope::string sockaddrs::addr() const
return address;
}
-/** Construct the object, sets everything to 0
- */
-sockaddrs::sockaddrs()
-{
- memset(this, 0, sizeof(*this));
-}
-
/** Check if this sockaddr has data in it
*/
bool sockaddrs::operator()() const
@@ -184,25 +193,96 @@ SocketEngineBase::~SocketEngineBase()
#endif
}
+/** Receive something from the buffer
+ * @param s The socket
+ * @param buf The buf to read to
+ * @param sz How much to read
+ * @return Number of bytes received
+ */
+int SocketIO::Recv(Socket *s, char *buf, size_t sz) const
+{
+ size_t i = recv(s->GetFD(), buf, sz, 0);
+ TotalRead += i;
+ return i;
+}
+
+/** Write something to the socket
+ * @param s The socket
+ * @param buf What to write
+ * @return Number of bytes written
+ */
+int SocketIO::Send(Socket *s, const Anope::string &buf) const
+{
+ size_t i = send(s->GetFD(), buf.c_str(), buf.length(), 0);
+ TotalWritten += i;
+ return i;
+}
+
+/** Accept a connection from a socket
+ * @param s The socket
+ */
+void SocketIO::Accept(ListenSocket *s)
+{
+ sockaddrs conaddr;
+
+ socklen_t size = conaddr.size();
+ int newsock = accept(s->GetFD(), &conaddr.sa, &size);
+
+#ifndef INVALID_SOCKET
+# define INVALID_SOCKET 0
+#endif
+
+ if (newsock > 0 && newsock != INVALID_SOCKET)
+ s->OnAccept(newsock, conaddr);
+ else
+ throw SocketException("Unable to accept connection: " + 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)
+{
+ 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());
+}
+
/** Empty constructor, used for things such as the pipe socket
*/
Socket::Socket()
{
+ this->Type = SOCKTYPE_BASE;
+ this->IO = &normalSocketIO;
}
/** Constructor
- * @param nsock The socket
- * @param nIPv6 IPv6?
+ * @param sock The socket
+ * @param ipv6 IPv6?
* @param type The socket type, defaults to SOCK_STREAM
*/
-Socket::Socket(int nsock, bool nIPv6, int type)
+Socket::Socket(int sock, bool ipv6, int type)
{
- Type = SOCKTYPE_CLIENT;
- IPv6 = nIPv6;
- if (nsock == 0)
- Sock = socket(IPv6 ? AF_INET6 : AF_INET, type, 0);
+ this->Type = SOCKTYPE_BASE;
+ this->IO = &normalSocketIO;
+ this->IPv6 = ipv6;
+ if (sock == 0)
+ this->Sock = socket(this->IPv6 ? AF_INET6 : AF_INET, type, 0);
else
- Sock = nsock;
+ this->Sock = sock;
SocketEngine->AddSocket(this);
}
@@ -212,34 +292,24 @@ Socket::~Socket()
{
if (SocketEngine)
SocketEngine->DelSocket(this);
- CloseSocket(Sock);
-}
-
-/** Really receive something from the buffer
- * @param buf The buf to read to
- * @param sz How much to read
- * @return Number of bytes received
- */
-int Socket::RecvInternal(char *buf, size_t sz) const
-{
- return recv(GetSock(), buf, sz, 0);
+ CloseSocket(this->Sock);
+ this->IO->Destroy();
}
-/** Really write something to the socket
- * @param buf What to write
- * @return Number of bytes written
+/** Get the socket FD for this socket
+ * @return the fd
*/
-int Socket::SendInternal(const Anope::string &buf) const
+int Socket::GetFD() const
{
- return send(GetSock(), buf.c_str(), buf.length(), 0);
+ return Sock;
}
-/** Get the socket FD for this socket
- * @return the fd
+/** Check if this socket is IPv6
+ * @return true or false
*/
-int Socket::GetSock() const
+bool Socket::IsIPv6() const
{
- return Sock;
+ return IPv6;
}
/** Mark a socket as blockig
@@ -249,10 +319,10 @@ bool Socket::SetBlocking()
{
#ifdef _WIN32
unsigned long opt = 0;
- return !ioctlsocket(this->GetSock(), FIONBIO, &opt);
+ return !ioctlsocket(this->GetFD(), FIONBIO, &opt);
#else
- int flags = fcntl(this->GetSock(), F_GETFL, 0);
- return !fcntl(this->GetSock(), F_SETFL, flags & ~O_NONBLOCK);
+ int flags = fcntl(this->GetFD(), F_GETFL, 0);
+ return !fcntl(this->GetFD(), F_SETFL, flags & ~O_NONBLOCK);
#endif
}
@@ -263,45 +333,67 @@ bool Socket::SetNonBlocking()
{
#ifdef _WIN32
unsigned long opt = 1;
- return !ioctlsocket(this->GetSock(), FIONBIO, &opt);
+ return !ioctlsocket(this->GetFD(), FIONBIO, &opt);
#else
- int flags = fcntl(this->GetSock(), F_GETFL, 0);
- return !fcntl(this->GetSock(), F_SETFL, flags | O_NONBLOCK);
+ int flags = fcntl(this->GetFD(), F_GETFL, 0);
+ return !fcntl(this->GetFD(), F_SETFL, flags | O_NONBLOCK);
#endif
}
-/** Check if this socket is IPv6
- * @return true or false
+/** Called when there is something to be received for this socket
+ * @return true on success, false to drop this socket
*/
-bool Socket::IsIPv6() const
+bool Socket::ProcessRead()
{
- return IPv6;
+ return true;
}
-/** Get the length of the read buffer
- * @return The length of the read buffer
+/** Called when the socket is ready to be written to
+ * @return true on success, false to drop this socket
*/
-size_t Socket::ReadBufferLen() const
+bool Socket::ProcessWrite()
{
- return RecvLen;
+ return true;
}
-/** Get the length of the write buffer
- * @return The length of the write buffer
+/** Called when there is an error for this socket
+ * @return true on success, false to drop this socket
*/
-size_t Socket::WriteBufferLen() const
+void Socket::ProcessError()
+{
+}
+
+/** Constructor for pipe socket
+ */
+BufferedSocket::BufferedSocket() : Socket()
+{
+ this->Type = SOCKTYPE_BUFFERED;
+}
+
+/** Constructor
+ * @param fd FD to use
+ * @param ipv6 true for ipv6
+ * @param type socket type, defaults to SOCK_STREAM
+ */
+BufferedSocket::BufferedSocket(int fd, bool ipv6, int type) : Socket(fd, ipv6, type)
+{
+ this->Type = SOCKTYPE_BUFFERED;
+}
+
+/** Default destructor
+ */
+BufferedSocket::~BufferedSocket()
{
- return WriteBuffer.length();
}
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
-bool Socket::ProcessRead()
+bool BufferedSocket::ProcessRead()
{
char tbuffer[NET_BUFSIZE] = "";
- RecvLen = RecvInternal(tbuffer, sizeof(tbuffer) - 1);
+ RecvLen = this->IO->Recv(this, tbuffer, sizeof(tbuffer) - 1);
if (RecvLen <= 0)
return false;
@@ -341,13 +433,13 @@ bool Socket::ProcessRead()
/** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
-bool Socket::ProcessWrite()
+bool BufferedSocket::ProcessWrite()
{
if (WriteBuffer.empty())
{
return true;
}
- if (SendInternal(WriteBuffer) == -1)
+ if (this->IO->Send(this, WriteBuffer) == -1)
{
return false;
}
@@ -357,18 +449,11 @@ bool Socket::ProcessWrite()
return true;
}
-/** Called when there is an error for this socket
- * @return true on success, false to drop this socket
- */
-void Socket::ProcessError()
-{
-}
-
/** Called with a line received from the socket
* @param buf The line
* @return true to continue reading, false to drop the socket
*/
-bool Socket::Read(const Anope::string &buf)
+bool BufferedSocket::Read(const Anope::string &buf)
{
return false;
}
@@ -376,7 +461,7 @@ bool Socket::Read(const Anope::string &buf)
/** Write to the socket
* @param message The message
*/
-void Socket::Write(const char *message, ...)
+void BufferedSocket::Write(const char *message, ...)
{
va_list vi;
char tbuffer[BUFSIZE];
@@ -395,58 +480,36 @@ void Socket::Write(const char *message, ...)
/** Write to the socket
* @param message The message
*/
-void Socket::Write(const Anope::string &message)
+void BufferedSocket::Write(const Anope::string &message)
{
WriteBuffer.append(message.str() + "\r\n");
SocketEngine->MarkWritable(this);
}
-/** Constructor
- * @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
- * @param nIPv6 true to use IPv6
- * @param type The socket type, defaults to SOCK_STREAM
- */
-ClientSocket::ClientSocket(const Anope::string &TargetHost, int Port, const Anope::string &BindHost, bool nIPv6, int type) : Socket(0, nIPv6, type)
-{
- this->SetNonBlocking();
-
- if (!BindHost.empty())
- {
- this->bindaddrs.pton(IPv6 ? AF_INET6 : AF_INET, BindHost, 0);
- if (bind(Sock, &this->bindaddrs.sa, this->bindaddrs.size()) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + Anope::LastError());
- }
-
- this->conaddrs.pton(IPv6 ? AF_INET6 : AF_INET, TargetHost, Port);
- if (connect(Sock, &this->conaddrs.sa, this->conaddrs.size()) == -1 && errno != EINPROGRESS)
- throw SocketException(Anope::string("Error connecting to server: ") + Anope::LastError());
-}
-
-/** Default destructor
+/** Get the length of the read buffer
+ * @return The length of the read buffer
*/
-ClientSocket::~ClientSocket()
+size_t BufferedSocket::ReadBufferLen() const
{
+ return RecvLen;
}
-/** Called with a line received from the socket
- * @param buf The line
- * @return true to continue reading, false to drop the socket
+/** Get the length of the write buffer
+ * @return The length of the write buffer
*/
-bool ClientSocket::Read(const Anope::string &buf)
+size_t BufferedSocket::WriteBufferLen() const
{
- return true;
+ return WriteBuffer.length();
}
/** Constructor
* @param bindip The IP to bind to
* @param port The port to listen on
+ * @param ipv6 true for ipv6
*/
-ListenSocket::ListenSocket(const Anope::string &bindip, int port) : Socket(0, (bindip.find(':') != Anope::string::npos ? true : false))
+ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool ipv6) : Socket(0, ipv6)
{
- Type = SOCKTYPE_LISTEN;
-
+ this->Type = SOCKTYPE_LISTEN;
this->SetNonBlocking();
this->listenaddrs.pton(IPv6 ? AF_INET6 : AF_INET, bindip, port);
@@ -468,24 +531,61 @@ ListenSocket::~ListenSocket()
*/
bool ListenSocket::ProcessRead()
{
- int newsock = accept(Sock, NULL, NULL);
+ try
+ {
+ this->IO->Accept(this);
+ }
+ catch (const SocketException &ex)
+ {
+ Log() << ex.GetReason();
+ }
+ return true;
+}
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET 0
-#endif
+/** Called when a connection is accepted
+ * @param fd The FD for the new connection
+ * @param addr The sockaddr for where the connection came from
+ * @return The new socket
+ */
+ClientSocket *ListenSocket::OnAccept(int fd, const sockaddrs &addr)
+{
+ return new ClientSocket(this, fd, addr);
+}
- if (newsock > 0 && newsock != INVALID_SOCKET)
- return this->OnAccept(new Socket(newsock, IPv6));
+/** Constructor
+ * @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)
+{
+ this->Type = SOCKTYPE_CONNECTION;
+}
- return true;
+/** 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)
+{
+ try
+ {
+ this->IO->Connect(this, TargetHost, Port, BindHost);
+ }
+ catch (const SocketException &)
+ {
+ delete this;
+ throw;
+ }
}
-/** Called when a connection is accepted
- * @param s The socket for the new connection
- * @return true if the listen socket should remain alive
+/** Constructor
+ * @param ls Listen socket this connection is from
+ * @param fd New FD for this socket
+ * @param addr Address the connection came from
*/
-bool ListenSocket::OnAccept(Socket *s)
+ClientSocket::ClientSocket(ListenSocket *ls, int fd, const sockaddrs &addr) : BufferedSocket(fd, ls->IsIPv6()), LS(ls), clientaddr(addr)
{
- return true;
+ this->Type = SOCKTYPE_CLIENT;
}
diff --git a/src/threadengine.cpp b/src/threadengine.cpp
index 36a73d324..0ac049c38 100644
--- a/src/threadengine.cpp
+++ b/src/threadengine.cpp
@@ -2,16 +2,39 @@
ThreadEngine threadEngine;
+/** Check for finished threads
+ */
+void ThreadEngine::Process()
+{
+ for (unsigned i = this->threads.size(); i > 0; --i)
+ {
+ Thread *t = this->threads[i - 1];
+
+ if (t->GetExitState())
+ {
+ t->Join();
+ delete t;
+ }
+ }
+}
+
/** Threads constructor
*/
Thread::Thread() : Exit(false)
{
+ threadEngine.threads.push_back(this);
}
/** Threads destructor
*/
Thread::~Thread()
{
+ std::vector<Thread *>::iterator it = std::find(threadEngine.threads.begin(), threadEngine.threads.end(), this);
+
+ if (it != threadEngine.threads.end())
+ {
+ threadEngine.threads.erase(it);
+ }
}
/** Sets the exit state as true informing the thread we want it to shut down
diff --git a/src/threadengines/threadengine_pthread.cpp b/src/threadengines/threadengine_pthread.cpp
index fb0b29506..65d1533f3 100644
--- a/src/threadengines/threadengine_pthread.cpp
+++ b/src/threadengines/threadengine_pthread.cpp
@@ -10,9 +10,7 @@ static void *entry_point(void *parameter)
{
Thread *thread = static_cast<Thread *>(parameter);
thread->Run();
- if (!thread->GetExitState())
- thread->Join();
- delete thread;
+ thread->SetExitState();
pthread_exit(0);
}
@@ -22,6 +20,8 @@ ThreadEngine::ThreadEngine()
{
if (pthread_attr_init(&threadengine_attr))
throw CoreException("ThreadEngine: Error calling pthread_attr_init");
+ if (pthread_attr_setdetachstate(&threadengine_attr, PTHREAD_CREATE_JOINABLE))
+ throw CoreException("ThreadEngine: Unable to mark threads as joinable");
}
/** Threadengines destructor
@@ -35,7 +35,7 @@ ThreadEngine::~ThreadEngine()
*/
void Thread::Join()
{
- SetExitState();
+ this->SetExitState();
pthread_join(Handle, NULL);
}
diff --git a/src/threadengines/threadengine_win32.cpp b/src/threadengines/threadengine_win32.cpp
index b67f01681..8fb103267 100644
--- a/src/threadengines/threadengine_win32.cpp
+++ b/src/threadengines/threadengine_win32.cpp
@@ -7,9 +7,7 @@ static DWORD WINAPI entry_point(void *parameter)
{
Thread *thread = static_cast<Thread *>(parameter);
thread->Run();
- if (!thread->GetExitState())
- thread->Join();
- delete thread;
+ thread->SetExitState();
return 0;
}
@@ -29,7 +27,7 @@ ThreadEngine::~ThreadEngine()
*/
void Thread::Join()
{
- SetExitState();
+ this->SetExitState();
WaitForSingleObject(Handle, INFINITE);
}
diff --git a/src/users.cpp b/src/users.cpp
index d4b1e15f2..b89e6c271 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -741,6 +741,7 @@ User *do_nick(const Anope::string &source, const Anope::string &nick, const Anop
if (!vhost.empty())
user->SetCloakedHost(vhost);
user->SetVIdent(username);
+ user->SetModesInternal(modes.c_str());
if (!ip.empty())
{