diff options
-rw-r--r-- | include/dns.h | 5 | ||||
-rw-r--r-- | include/extern.h | 14 | ||||
-rw-r--r-- | include/modules.h | 8 | ||||
-rw-r--r-- | include/sockets.h | 260 | ||||
-rw-r--r-- | include/threadengine.h | 7 | ||||
-rw-r--r-- | modules/extra/db_mysql.cpp | 2 | ||||
-rw-r--r-- | modules/extra/m_mysql.cpp | 8 | ||||
-rw-r--r-- | modules/extra/m_ssl.cpp | 246 | ||||
-rw-r--r-- | modules/extra/ssl.h | 9 | ||||
-rw-r--r-- | modules/socketengines/m_socketengine_epoll.cpp | 8 | ||||
-rw-r--r-- | modules/socketengines/m_socketengine_select.cpp | 26 | ||||
-rwxr-xr-x | src/bin/mydbgen | 1 | ||||
-rw-r--r-- | src/dns.cpp | 15 | ||||
-rw-r--r-- | src/mail.cpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 40 | ||||
-rw-r--r-- | src/misc.cpp | 2 | ||||
-rw-r--r-- | src/modules.cpp | 1 | ||||
-rw-r--r-- | src/socketengines/socketengine_eventfd.cpp | 41 | ||||
-rw-r--r-- | src/socketengines/socketengine_pipe.cpp | 3 | ||||
-rw-r--r-- | src/socketengines/socketengine_win32.cpp | 7 | ||||
-rw-r--r-- | src/sockets.cpp | 324 | ||||
-rw-r--r-- | src/threadengine.cpp | 23 | ||||
-rw-r--r-- | src/threadengines/threadengine_pthread.cpp | 8 | ||||
-rw-r--r-- | src/threadengines/threadengine_win32.cpp | 6 | ||||
-rw-r--r-- | src/users.cpp | 1 |
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()) { |