From e2af2347fc035d702e45f12e772223a8d578410d Mon Sep 17 00:00:00 2001 From: danieldg Date: Mon, 21 Sep 2009 13:26:31 +0000 Subject: [PATCH] Create StreamSocket for IO hooking implementation Fixes the SSL SendQ bug Removes duplicate code between User and BufferedSocket Simplify SSL module API Simplify EventHandler API (Readable/Writeable moved to SE) Add hook for culled objects to invoke callbacks prior to destructor Replace SocketCull with GlobalCull now that sockets can close themselves Shorten common case of user read/parse/write path: User::Write is now zero-copy up to syscall/SSL invocation User::Read has only two copy/scan passes from read() to ProcessCommand git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11752 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/base.h | 4 +- include/cull_list.h | 9 +- include/inspircd.h | 19 - include/inspsocket.h | 327 +++------- include/modules.h | 59 +- include/socket.h | 2 +- include/socketengine.h | 84 +-- include/socketengines/socketengine_epoll.h | 9 +- include/socketengines/socketengine_iocp.h | 6 +- include/socketengines/socketengine_kqueue.h | 9 +- include/socketengines/socketengine_poll.h | 7 +- include/socketengines/socketengine_ports.h | 8 +- include/socketengines/socketengine_select.h | 8 +- include/users.h | 75 +-- src/base.cpp | 8 + src/command_parse.cpp | 36 +- src/cull_list.cpp | 8 +- src/helperfuncs.cpp | 12 +- src/inspircd.cpp | 23 +- src/inspsocket.cpp | 567 +++++++----------- src/modules.cpp | 12 +- src/modules/extra/m_ssl_gnutls.cpp | 227 +++---- src/modules/extra/m_ssl_openssl.cpp | 182 +++--- src/modules/extra/m_ziplink.cpp | 111 ++-- src/modules/m_httpd.cpp | 45 +- src/modules/m_spanningtree/addline.cpp | 10 +- src/modules/m_spanningtree/admin.cpp | 14 +- src/modules/m_spanningtree/away.cpp | 2 +- src/modules/m_spanningtree/capab.cpp | 14 +- src/modules/m_spanningtree/compat.cpp | 2 +- src/modules/m_spanningtree/delline.cpp | 2 +- src/modules/m_spanningtree/encap.cpp | 2 +- src/modules/m_spanningtree/fhost.cpp | 2 +- src/modules/m_spanningtree/fident.cpp | 2 +- src/modules/m_spanningtree/fjoin.cpp | 8 +- src/modules/m_spanningtree/fmode.cpp | 6 +- src/modules/m_spanningtree/fname.cpp | 2 +- src/modules/m_spanningtree/ftopic.cpp | 4 +- src/modules/m_spanningtree/handshaketimer.cpp | 6 +- src/modules/m_spanningtree/hmac.cpp | 4 +- src/modules/m_spanningtree/kill.cpp | 4 +- src/modules/m_spanningtree/main.cpp | 5 +- src/modules/m_spanningtree/metadata.cpp | 10 +- src/modules/m_spanningtree/modules.cpp | 4 +- src/modules/m_spanningtree/motd.cpp | 14 +- src/modules/m_spanningtree/netburst.cpp | 32 +- src/modules/m_spanningtree/nickcollide.cpp | 2 +- src/modules/m_spanningtree/operquit.cpp | 2 +- src/modules/m_spanningtree/opertype.cpp | 8 +- src/modules/m_spanningtree/override_stats.cpp | 4 +- src/modules/m_spanningtree/ping.cpp | 4 +- src/modules/m_spanningtree/pong.cpp | 2 +- src/modules/m_spanningtree/push.cpp | 2 +- src/modules/m_spanningtree/resolvers.cpp | 5 +- src/modules/m_spanningtree/save.cpp | 4 +- src/modules/m_spanningtree/server.cpp | 46 +- src/modules/m_spanningtree/stats.cpp | 8 +- src/modules/m_spanningtree/svsjoin.cpp | 4 +- src/modules/m_spanningtree/svsnick.cpp | 4 +- src/modules/m_spanningtree/svspart.cpp | 4 +- src/modules/m_spanningtree/time.cpp | 10 +- src/modules/m_spanningtree/treesocket.h | 31 +- src/modules/m_spanningtree/treesocket1.cpp | 128 ++-- src/modules/m_spanningtree/treesocket2.cpp | 32 +- src/modules/m_spanningtree/uid.cpp | 14 +- src/modules/m_spanningtree/utils.cpp | 29 +- src/modules/m_spanningtree/utils.h | 3 + src/modules/m_spanningtree/whois.cpp | 6 +- src/socket.cpp | 2 +- src/socketengine.cpp | 61 +- src/socketengines/socketengine_epoll.cpp | 7 +- src/socketengines/socketengine_iocp.cpp | 6 +- src/socketengines/socketengine_kqueue.cpp | 6 +- src/socketengines/socketengine_poll.cpp | 10 +- src/socketengines/socketengine_ports.cpp | 6 +- src/socketengines/socketengine_select.cpp | 15 +- src/stats.cpp | 4 +- src/threadengines/threadengine_pthread.cpp | 33 +- src/threadengines/threadengine_win32.cpp | 17 +- src/usermanager.cpp | 27 +- src/userprocess.cpp | 104 +--- src/users.cpp | 284 +++------ 82 files changed, 990 insertions(+), 1950 deletions(-) diff --git a/include/base.h b/include/base.h index ab52545f9..b66051caf 100644 --- a/include/base.h +++ b/include/base.h @@ -28,7 +28,9 @@ class CoreExport classbase public: classbase(); - virtual ~classbase() { } + // Called just prior to destruction via cull list + virtual void cull(); + virtual ~classbase(); }; /** BoolSet is a utility class designed to hold eight bools in a bitmask. diff --git a/include/cull_list.h b/include/cull_list.h index 8c3827642..bd2fb45da 100644 --- a/include/cull_list.h +++ b/include/cull_list.h @@ -19,17 +19,14 @@ * avoid problems with references to deleted pointers if an object were deleted * during execution. */ -class CoreExport CullList : public classbase +class CoreExport CullList { - private: - std::vector list; + std::set list; public: - CullList() {} - /** Adds an item to the cull list */ - void AddItem(classbase* item) { list.push_back(item); } + void AddItem(classbase* item) { list.insert(item); } /** Applies the cull list (deletes the contents) */ diff --git a/include/inspircd.h b/include/inspircd.h index b927f0b1b..72e49c09a 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -277,7 +277,6 @@ class serverstats : public classbase class InspIRCd; -DEFINE_HANDLER1(ProcessUserHandler, void, User*); DEFINE_HANDLER2(IsNickHandler, bool, const char*, size_t); DEFINE_HANDLER1(IsIdentHandler, bool, const char*); DEFINE_HANDLER1(FloodQuitUserHandler, void, User*); @@ -386,7 +385,6 @@ class CoreExport InspIRCd : public classbase /**** Functors ****/ - ProcessUserHandler HandleProcessUser; IsNickHandler HandleIsNick; IsIdentHandler HandleIsIdent; FloodQuitUserHandler HandleFloodQuitUser; @@ -394,11 +392,6 @@ class CoreExport InspIRCd : public classbase IsSIDHandler HandleIsSID; RehashHandler HandleRehash; - /** BufferedSocket classes pending deletion after being closed. - * We don't delete these immediately as this may cause a segmentation fault. - */ - std::map SocketCull; - /** Globally accessible fake user record. This is used to force mode changes etc across s2s, etc.. bit ugly, but.. better than how this was done in 1.1 * Reason for it: * kludge alert! @@ -527,13 +520,6 @@ class CoreExport InspIRCd : public classbase */ time_t Time(); - /** Process a user whos socket has been flagged as active - * @param cu The user to process - * @return There is no actual return value, however upon exit, the user 'cu' may have been - * marked for deletion in the global CullList. - */ - caller1 ProcessUser; - /** Bind all ports specified in the configuration file. * @return The number of ports bound without error */ @@ -924,11 +910,6 @@ class CoreExport InspIRCd : public classbase */ int Run(); - /** Force all BufferedSockets to be removed which are due to - * be culled. - */ - void BufferedSocketCull(); - /** Adds an extban char to the 005 token. */ void AddExtBanChar(char c); diff --git a/include/inspsocket.h b/include/inspsocket.h index 32f2dab1a..73aa748a0 100644 --- a/include/inspsocket.h +++ b/include/inspsocket.h @@ -36,6 +36,10 @@ enum BufferedSocketState */ enum BufferedSocketError { + /** No error */ + I_ERR_NONE, + /** Socket was closed by peer */ + I_ERR_DISCONNECT, /** Socket connect timed out */ I_ERR_TIMEOUT, /** Socket could not be created */ @@ -44,17 +48,16 @@ enum BufferedSocketError I_ERR_CONNECT, /** Socket could not bind to local port/ip */ I_ERR_BIND, - /** Socket could not reslve host (depreciated) */ - I_ERR_RESOLVE, /** Socket could not write data */ I_ERR_WRITE, /** No more file descriptors left to create socket! */ - I_ERR_NOMOREFDS + I_ERR_NOMOREFDS, + /** Some other error */ + I_ERR_OTHER }; /* Required forward declarations */ class BufferedSocket; -class InspIRCd; /** Used to time out socket connections */ @@ -65,10 +68,6 @@ class CoreExport SocketTimeout : public Timer */ BufferedSocket* sock; - /** Server instance creating the timeout class - */ - InspIRCd* ServerInstance; - /** File descriptor of class this is attached to */ int sfd; @@ -81,13 +80,74 @@ class CoreExport SocketTimeout : public Timer * @param secs_from_now Seconds from now to time out * @param now The current time */ - SocketTimeout(int fd, InspIRCd* Instance, BufferedSocket* thesock, long secs_from_now, time_t now) : Timer(secs_from_now, now), sock(thesock), ServerInstance(Instance), sfd(fd) { }; + SocketTimeout(int fd, BufferedSocket* thesock, long secs_from_now, time_t now) : Timer(secs_from_now, now), sock(thesock), sfd(fd) { } /** Handle tick event */ virtual void Tick(time_t now); }; +/** + * StreamSocket is a class that wraps a TCP socket and handles send + * and receive queues, including passing them to IO hooks + */ +class CoreExport StreamSocket : public EventHandler +{ + /** Module that handles raw I/O for this socket, or NULL */ + Module *IOHook; + /** Private send queue. Note that individual strings may be shared + */ + std::deque sendq; + /** Length, in bytes, of the sendq */ + size_t sendq_len; + /** Error - if nonempty, the socket is dead, and this is the reason. */ + std::string error; + protected: + std::string recvq; + public: + StreamSocket() : IOHook(NULL), sendq_len(0) {} + inline Module* GetIOHook() { return IOHook; } + inline void AddIOHook(Module* m) { IOHook = m; } + inline void DelIOHook() { IOHook = NULL; } + /** Handle event from socket engine. + * This will call OnDataReady if there is *new* data in recvq + */ + virtual void HandleEvent(EventType et, int errornum = 0); + /** Dispatched from HandleEvent */ + virtual void DoRead(); + /** Dispatched from HandleEvent */ + virtual void DoWrite(); + + /** Sets the error message for this socket. Once set, the socket is dead. */ + void SetError(const std::string& err) { if (error.empty()) error = err; } + + /** Gets the error message for this socket. */ + const std::string& getError() const { return error; } + + /** Called when new data is present in recvq */ + virtual void OnDataReady() = 0; + /** Called when the socket gets an error from socket engine or IO hook */ + virtual void OnError(BufferedSocketError e) = 0; + + /** Send the given data out the socket, either now or when writes unblock + */ + void WriteData(const std::string& data); + /** Convenience function: read a line from the socket + * @param line The line read + * @param delim The line delimiter + * @return true if a line was read + */ + bool GetNextLine(std::string& line, char delim = '\n'); + /** Useful for implementing sendq exceeded */ + inline const size_t getSendQSize() const { return sendq_len; } + + /** + * Close the socket, remove from socket engine, etc + */ + virtual void Close(); + /** This ensures that close is called prior to destructor */ + virtual void cull(); +}; /** * BufferedSocket is an extendable socket class which modules * can use for TCP socket support. It is fully integrated @@ -97,34 +157,13 @@ class CoreExport SocketTimeout : public Timer * * To use BufferedSocket, you must inherit a class from it. */ -class CoreExport BufferedSocket : public EventHandler +class CoreExport BufferedSocket : public StreamSocket { public: - - /** Bind IP - */ - std::string cbindip; - - /** Instance we were created by - */ - InspIRCd* ServerInstance; - - /** Timeout class or NULL + /** Timeout object or NULL */ SocketTimeout* Timeout; - /** Socket output buffer (binary safe) - */ - std::deque outbuffer; - - /** The hostname connected to - */ - char host[MAXBUF]; - - /** The port connected to - */ - int port; - /** * The state for this socket, either * listening, connecting, connected @@ -132,220 +171,52 @@ class CoreExport BufferedSocket : public EventHandler */ BufferedSocketState state; - /** - * The IP address being connected - * to stored in string form for - * easy retrieval by accessors. - */ - char IP[MAXBUF]; - - /** - * Used by accept() to indicate the - * sizes of the sockaddr_in structures - */ - socklen_t length; - - /** Flushes the write buffer - * @returns true if the writing failed, false if it was successful - */ - bool FlushWriteBuffer(); - - /** Set the queue sizes - * This private method sets the operating system queue - * sizes for this socket to 65535 so that it can queue - * more information without application-level queueing - * which was required in older software. - */ - void SetQueues(); - - /** When the socket has been marked as closing, this flag - * will be set to true, then the next time the socket is - * examined, the socket is deleted and closed. - */ - bool ClosePending; - - /** - * Bind to an address - * @param ip IP to bind to - * @return True is the binding succeeded - */ - bool BindAddr(const std::string &ip); - - /** (really) Try bind to a given IP setup. For internal use only. - */ - bool DoBindMagic(const std::string ¤t_ip); - - /** - * The default constructor does nothing - * and should not be used. - */ - BufferedSocket(InspIRCd* SI); - + BufferedSocket(); /** * This constructor is used to associate * an existing connecting with an BufferedSocket * class. The given file descriptor must be * valid, and when initialized, the BufferedSocket - * will be set with the given IP address - * and placed in CONNECTED state. - */ - BufferedSocket(InspIRCd* SI, int newfd, const char* ip); - - /** - * This constructor is used to create a new outbound connection to another host. - * Note that if you specify a hostname in the 'ipaddr' parameter, this class will not - * connect. You must resolve your hostnames before passing them to BufferedSocket. To do so, - * you should use the nonblocking class 'Resolver'. - * @param ipaddr The IP to connect to, or bind to - * @param port The port number to connect to - * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated - * @param connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound. - * @return On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error. - */ - BufferedSocket(InspIRCd* SI, const std::string &ipaddr, int port, unsigned long maxtime, const std::string &connectbindip = ""); - - /** - * This method is called when an outbound - * connection on your socket is completed. - * @return false to abort the connection, true to continue - */ - virtual bool OnConnected(); - - /** - * This method is called when an error occurs. - * A closed socket in itself is not an error, - * however errors also generate close events. - * @param e The error type which occured + * will be placed in CONNECTED state. */ - virtual void OnError(BufferedSocketError e); + BufferedSocket(int newfd); - /** - * When an established connection is terminated, - * the OnDisconnect method is triggered. + /** Begin connection to the given address + * This will create a socket, register with socket engine, and start the asynchronous + * connection process. If an error is detected at this point (such as out of file descriptors), + * OnError will be called; otherwise, the state will become CONNECTING. + * @param dest Address to connect to + * @param bind Address to bind to (if NULL, no bind will be done) + * @param timeout Time to wait for connection */ - virtual int OnDisconnect(); + void DoConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip); - /** - * When there is data waiting to be read on a - * socket, the OnDataReady() method is called. - * Within this method, you *MUST* call the Read() - * method to read any pending data. At its lowest - * level, this event is signalled by the core via - * the socket engine. If you return false from this - * function, the core removes your socket from its - * list and erases it from the socket engine, then - * calls BufferedSocket::Close() and deletes it. - * @return false to close the socket + /** This method is called when an outbound connection on your socket is + * completed. */ - virtual bool OnDataReady(); + virtual void OnConnected(); - /** - * When it is ok to write to the socket, and a - * write event was requested, this method is - * triggered. - * - * Within this method you should call - * write() or send() etc, to send data to the - * other end of the socket. - * - * Further write events will not be triggered - * unless you call SocketEngine::WantWrite(). - * - * The default behaviour of this method is to - * flush the write buffer, respecting the IO - * hooking modules. - * - * XXX: this used to be virtual, ask us if you need it to be so. - * @return false to close the socket + /** When there is data waiting to be read on a socket, the OnDataReady() + * method is called. */ - bool OnWriteReady(); + virtual void OnDataReady() = 0; /** - * When an outbound connection fails, and the - * attempt times out, you will receive this event. - * The method will trigger once maxtime seconds are - * reached (as given in the constructor) just - * before the socket's descriptor is closed. - * A failed DNS lookup may cause this event if - * the DNS server is not responding, as well as - * a failed connect() call, because DNS lookups are - * nonblocking as implemented by this class. + * When an outbound connection fails, and the attempt times out, you + * will receive this event. The method will trigger once maxtime + * seconds are reached (as given in the constructor) just before the + * socket's descriptor is closed. A failed DNS lookup may cause this + * event if the DNS server is not responding, as well as a failed + * connect() call, because DNS lookups are nonblocking as implemented by + * this class. */ virtual void OnTimeout(); - /** - * Whenever close() is called, OnClose() will be - * called first. Please note that this means - * OnClose will be called alongside OnError(), - * OnTimeout(), and Close(). - */ - virtual void OnClose(); - - /** - * Reads all pending bytes from the socket - * into a char* array which can be up to - * 16 kilobytes in length. - */ - virtual const char* Read(); - - /** - * Returns the IP address associated with - * this connection, or an empty string if - * no IP address exists. - */ - std::string GetIP(); - - /** - * Writes a std::string to the socket. No carriage - * returns or linefeeds are appended to the string. - * @param data The data to send - */ - virtual void Write(const std::string &data); - - /** - * Changes the socket's state. The core uses this - * to change socket states, and you should not call - * it directly. - */ - void SetState(BufferedSocketState s); - - /** - * Returns the current socket state. - */ - BufferedSocketState GetState(); - - /** Mark a socket as being connected and call appropriate events. - */ - bool InternalMarkConnected(); - - /** - * This method causes the socket to close, and may - * also be triggered by other methods such as OnTimeout - * and OnError. - */ - virtual void Close(); - - /** - * The destructor may implicitly call OnClose(), and - * will close() and shutdown() the file descriptor - * used for this socket. - */ virtual ~BufferedSocket(); - - /** - * This method attempts to connect to a hostname. - * This method is asyncronous. - * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated - */ - virtual bool DoConnect(unsigned long maxtime); - - /** Handle event from EventHandler parent class - */ - void HandleEvent(EventType et, int errornum = 0); - - /** Returns true if this socket is readable - */ - bool Readable(); + protected: + virtual void DoWrite(); + BufferedSocketError BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned long timeout); + BufferedSocketError BeginConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip); }; #endif diff --git a/include/modules.h b/include/modules.h index f40cd49fd..982d83754 100644 --- a/include/modules.h +++ b/include/modules.h @@ -406,10 +406,9 @@ enum Implementation I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckChannelBan, I_OnExtBanCheck, I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnPreTopicChange, I_OnPostTopicChange, I_OnEvent, I_OnRequest, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, - I_OnDelBan, I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketWrite, I_OnRawSocketRead, - I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete, + I_OnDelBan, I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete, I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnUserList, I_OnPostCommand, I_OnPostJoin, - I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed, + I_OnWhoisLine, I_OnBuildExemptList, I_OnGarbageCollect, I_OnBufferFlushed, I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO, I_OnHostCycle, I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, I_END @@ -1242,9 +1241,9 @@ class CoreExport Module : public Extensible * @param user The item to possibly install the I/O hook on * @param via The port that connected on */ - virtual void OnHookIO(EventHandler* user, ListenSocketBase* via); + virtual void OnHookIO(StreamSocket*, ListenSocketBase* via); - /** Called immediately after any connection is accepted. This is intended for raw socket + /** Called immediately after any connection is accepted. This is intended for raw socket * processing (e.g. modules which wrap the tcp connection within another library) and provides * no information relating to a user record as the connection has not been assigned yet. * There are no return values from this call as all modules get an opportunity if required to @@ -1254,48 +1253,38 @@ class CoreExport Module : public Extensible * @param server The server IP address and port * @param localport The local port number the user connected to */ - virtual void OnRawSocketAccept(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); + virtual void OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); - /** Called immediately before any write() operation on a user's socket in the core. Because - * this event is a low level event no user information is associated with it. It is intended - * for use by modules which may wrap connections within another API such as SSL for example. - * return a non-zero result if you have handled the write operation, in which case the core - * will not call write(). - * @param fd The file descriptor of the socket - * @param buffer A char* buffer being written - * @param Number of characters to write - * @return Number of characters actually written or 0 if you didn't handle the operation + /** + * Called when a hooked stream has data to write, or when the socket + * engine returns it as writable + * @param socket The socket in question + * @param sendq Data to send to the socket + * @return 1 if the sendq has been completely emptied, 0 if there is + * still data to send, and -1 if there was an error */ - virtual int OnRawSocketWrite(int fd, const char* buffer, int count); + virtual int OnStreamSocketWrite(StreamSocket*, std::string& sendq); /** Called immediately before any socket is closed. When this event is called, shutdown() * has not yet been called on the socket. * @param fd The file descriptor of the socket prior to close() */ - virtual void OnRawSocketClose(int fd); + virtual void OnStreamSocketClose(StreamSocket*); /** Called immediately upon connection of an outbound BufferedSocket which has been hooked * by a module. * @param fd The file descriptor of the socket immediately after connect() */ - virtual void OnRawSocketConnect(int fd); - - /** Called immediately before any read() operation on a client socket in the core. - * This occurs AFTER the select() or poll() so there is always data waiting to be read - * when this event occurs. - * Your event should return 1 if it has handled the reading itself, which prevents the core - * just using read(). You should place any data read into buffer, up to but NOT GREATER THAN - * the value of count. The value of readresult must be identical to an actual result that might - * be returned from the read() system call, for example, number of bytes read upon success, - * 0 upon EOF or closed socket, and -1 for error. If your function returns a nonzero value, - * you MUST set readresult. - * @param fd The file descriptor of the socket - * @param buffer A char* buffer being read to - * @param count The size of the buffer - * @param readresult The amount of characters read, or 0 - * @return nonzero if the event was handled, in which case readresult must be valid on exit - */ - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult); + virtual void OnStreamSocketConnect(StreamSocket*); + + /** + * Called when the stream socket has data to read + * @param socket The socket that is ready + * @param recvq The receive queue that new data should be appended to + * @return 1 if new data has been read, 0 if no new data is ready (but the + * socket is still connected), -1 if there was an error or close + */ + virtual int OnStreamSocketRead(StreamSocket*, std::string& recvq); /** Called whenever a user sets away or returns from being away. * The away message is available as a parameter, but should not be modified. diff --git a/include/socket.h b/include/socket.h index 5ca9fc18f..af3eccea2 100644 --- a/include/socket.h +++ b/include/socket.h @@ -99,7 +99,7 @@ namespace irc CoreExport int OpenTCPSocket(const char* addr, int socktype = SOCK_STREAM); /** Return the size of the structure for syscall passing */ - CoreExport int sa_size(irc::sockets::sockaddrs& sa); + CoreExport int sa_size(const irc::sockets::sockaddrs& sa); /** Convert an address-port pair into a binary sockaddr * @param addr The IP address, IPv4 or IPv6 diff --git a/include/socketengine.h b/include/socketengine.h index a191ff12d..4e87f7494 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -69,32 +69,11 @@ class CoreExport EventHandler : public Extensible * other forms of IPC. */ int fd; - - /** Pointer to the module which has hooked the given EventHandler for IO events. - */ - Module *IOHook; public: - - /** Return the current hooker of IO events for this socket, or NULL. - * @return Hooker module, if set, or NULL. - */ - Module *GetIOHook(); - - /** Set a module as hooking IO events on this socket. - * @param IOHooker The module hooking IO - * @return True if the hook could be added, false otherwise. - */ - bool AddIOHook(Module *IOHooker); - - /** Remove IO hooking from a module - * @return True if hooking was successfully removed, false otherwise. - */ - bool DelIOHook(); - /** Get the current file descriptor * @return The file descriptor of this handler */ - int GetFd(); + inline int GetFd() const { return fd; } /** Set a new file desciptor * @param FD The new file descriptor. Do not @@ -112,44 +91,10 @@ class CoreExport EventHandler : public Extensible */ virtual ~EventHandler() {} - /** Override this function to indicate readability. - * @return This should return true if the function - * wishes to receive EVENT_READ events. Do not change - * what this function returns while the event handler - * is still added to a SocketEngine instance! - * If this function is unimplemented, the base class - * will return true. - * - * NOTE: You cannot set both Readable() and - * Writeable() to true. If you wish to receive - * a write event for your object, you must call - * SocketEngine::WantWrite() instead. This will - * trigger your objects next EVENT_WRITE type event. - */ - virtual bool Readable(); - - /** Override this function to indicate writeability. - * @return This should return true if the function - * wishes to receive EVENT_WRITE events. Do not change - * what this function returns while the event handler - * is still added to a SocketEngine instance! - * If this function is unimplemented, the base class - * will return false. - * - * NOTE: You cannot set both Readable() and - * Writeable() to true. If you wish to receive - * a write event for your object, you must call - * SocketEngine::WantWrite() instead. This will - * trigger your objects next EVENT_WRITE type event. - */ - virtual bool Writeable(); - /** Process an I/O event. * You MUST implement this function in your derived * class, and it will be called whenever read or write - * events are received, depending on what your functions - * Readable() and Writeable() returns and wether you - * previously made a call to SocketEngine::WantWrite(). + * events are received. * @param et either one of EVENT_READ for read events, * and EVENT_WRITE for write events. */ @@ -177,9 +122,6 @@ class CoreExport EventHandler : public Extensible class CoreExport SocketEngine { protected: - /** Owner/Creator - */ - InspIRCd* ServerInstance; /** Handle to socket engine, where needed. */ int EngineHandle; @@ -211,9 +153,8 @@ public: * failure (for example, you try and enable * epoll on a 2.4 linux kernel) then this * function may bail back to the shell. - * @param Instance The creator/owner of this object */ - SocketEngine(InspIRCd* Instance); + SocketEngine(); /** Destructor. * The destructor transparently tidies up @@ -221,15 +162,14 @@ public: */ virtual ~SocketEngine(); - /** Add an EventHandler object to the engine. - * Use AddFd to add a file descriptor to the - * engine and have the socket engine monitor - * it. You must provide an object derived from - * EventHandler which implements HandleEvent() - * and optionally Readable() and Writeable(). + /** Add an EventHandler object to the engine. Use AddFd to add a file + * descriptor to the engine and have the socket engine monitor it. You + * must provide an object derived from EventHandler which implements + * HandleEvent(). * @param eh An event handling object to add + * @param writeFirst Wait for a write event instead of a read */ - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false) = 0; /** If you call this function and pass it an * event handler, that event handler will @@ -242,7 +182,7 @@ public: * @param eh An event handler which wants to * receive the next writeability event. */ - virtual void WantWrite(EventHandler* eh); + virtual void WantWrite(EventHandler* eh) = 0; /** Returns the maximum number of file descriptors * you may store in the socket engine at any one time. @@ -273,7 +213,7 @@ public: * @param force *DANGEROUS* See method description! * @return True if the event handler was removed */ - virtual bool DelFd(EventHandler* eh, bool force = false); + virtual bool DelFd(EventHandler* eh, bool force = false) = 0; /** Returns true if a file descriptor exists in * the socket engine's list. @@ -305,7 +245,7 @@ public: * in /VERSION responses. * @return The socket engine name */ - virtual std::string GetName(); + virtual std::string GetName() = 0; /** Returns true if the file descriptors in the * given event handler are within sensible ranges diff --git a/include/socketengines/socketengine_epoll.h b/include/socketengines/socketengine_epoll.h index 6e6818212..3e08179ae 100644 --- a/include/socketengines/socketengine_epoll.h +++ b/include/socketengines/socketengine_epoll.h @@ -23,8 +23,6 @@ #include #define EP_DELAY 5 -class InspIRCd; - /** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll(). */ class EPollEngine : public SocketEngine @@ -35,13 +33,12 @@ private: struct epoll_event* events; public: /** Create a new EPollEngine - * @param Instance The creator of this object */ - EPollEngine(InspIRCd* Instance); + EPollEngine(); /** Delete an EPollEngine */ virtual ~EPollEngine(); - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false); virtual int GetMaxFds(); virtual int GetRemainingFds(); virtual bool DelFd(EventHandler* eh, bool force = false); @@ -57,7 +54,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on EpollEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new EPollEngine(Instance); } + SocketEngine* Create() { return new EPollEngine; } }; #endif diff --git a/include/socketengines/socketengine_iocp.h b/include/socketengines/socketengine_iocp.h index 302fdbd2c..dd34227d3 100644 --- a/include/socketengines/socketengine_iocp.h +++ b/include/socketengines/socketengine_iocp.h @@ -121,7 +121,7 @@ public: /** Creates an IOCP Socket Engine * @param Instance The creator of this object */ - IOCPEngine(InspIRCd* Instance); + IOCPEngine(); /** Deletes an IOCP socket engine and all the attached sockets */ @@ -131,7 +131,7 @@ public: * @param eh EventHandler to add * @return True if success, false if no room */ - bool AddFd(EventHandler* eh); + bool AddFd(EventHandler* eh, bool writeFirst = false); /** Gets the maximum number of file descriptors that this engine can handle. * @return The number of file descriptors @@ -234,7 +234,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on IOCPEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new IOCPEngine(Instance); } + SocketEngine* Create() { return new IOCPEngine; } }; #endif diff --git a/include/socketengines/socketengine_kqueue.h b/include/socketengines/socketengine_kqueue.h index 41459f561..a09e93553 100644 --- a/include/socketengines/socketengine_kqueue.h +++ b/include/socketengines/socketengine_kqueue.h @@ -24,8 +24,6 @@ #include #include "socketengine.h" -class InspIRCd; - /** A specialisation of the SocketEngine class, designed to use FreeBSD kqueue(). */ class KQueueEngine : public SocketEngine @@ -39,13 +37,12 @@ private: struct timespec ts; public: /** Create a new KQueueEngine - * @param Instance The creator of this object */ - KQueueEngine(InspIRCd* Instance); + KQueueEngine(); /** Delete a KQueueEngine */ virtual ~KQueueEngine(); - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false); virtual int GetMaxFds(); virtual int GetRemainingFds(); virtual bool DelFd(EventHandler* eh, bool force = false); @@ -62,7 +59,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on KQueueEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new KQueueEngine(Instance); } + SocketEngine* Create() { return new KQueueEngine; } }; #endif diff --git a/include/socketengines/socketengine_poll.h b/include/socketengines/socketengine_poll.h index df1100d09..725ad225c 100644 --- a/include/socketengines/socketengine_poll.h +++ b/include/socketengines/socketengine_poll.h @@ -48,13 +48,12 @@ private: std::map fd_mappings; public: /** Create a new PollEngine - * @param Instance The creator of this object */ - PollEngine(InspIRCd* Instance); + PollEngine(); /** Delete a PollEngine */ virtual ~PollEngine(); - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false); virtual EventHandler* GetRef(int fd); virtual int GetMaxFds(); virtual int GetRemainingFds(); @@ -71,7 +70,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on PollEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new PollEngine(Instance); } + SocketEngine* Create() { return new PollEngine; } }; #endif diff --git a/include/socketengines/socketengine_ports.h b/include/socketengines/socketengine_ports.h index 40d5da51a..03df456f2 100644 --- a/include/socketengines/socketengine_ports.h +++ b/include/socketengines/socketengine_ports.h @@ -26,8 +26,6 @@ #include "socketengine.h" #include -class InspIRCd; - /** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports */ class PortsEngine : public SocketEngine @@ -40,11 +38,11 @@ public: /** Create a new PortsEngine * @param Instance The creator of this object */ - PortsEngine(InspIRCd* Instance); + PortsEngine(); /** Delete a PortsEngine */ virtual ~PortsEngine(); - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false); virtual int GetMaxFds(); virtual int GetRemainingFds(); virtual bool DelFd(EventHandler* eh, bool force = false); @@ -60,7 +58,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on PortsEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new PortsEngine(Instance); } + SocketEngine* Create() { return new PortsEngine; } }; #endif diff --git a/include/socketengines/socketengine_select.h b/include/socketengines/socketengine_select.h index a248e8a8e..a1993f19f 100644 --- a/include/socketengines/socketengine_select.h +++ b/include/socketengines/socketengine_select.h @@ -24,8 +24,6 @@ #include "inspircd.h" #include "socketengine.h" -class InspIRCd; - /** A specialisation of the SocketEngine class, designed to use traditional select(). */ class SelectEngine : public SocketEngine @@ -45,11 +43,11 @@ public: /** Create a new SelectEngine * @param Instance The creator of this object */ - SelectEngine(InspIRCd* Instance); + SelectEngine(); /** Delete a SelectEngine */ virtual ~SelectEngine(); - virtual bool AddFd(EventHandler* eh); + virtual bool AddFd(EventHandler* eh, bool writeFirst = false); virtual int GetMaxFds(); virtual int GetRemainingFds(); virtual bool DelFd(EventHandler* eh, bool force = false); @@ -65,7 +63,7 @@ class SocketEngineFactory public: /** Create a new instance of SocketEngine based on SelectEngine */ - SocketEngine* Create(InspIRCd* Instance) { return new SelectEngine(Instance); } + SocketEngine* Create() { return new SelectEngine; } }; #endif diff --git a/include/users.h b/include/users.h index f9be74924..7ec35535f 100644 --- a/include/users.h +++ b/include/users.h @@ -15,6 +15,7 @@ #define __USERS_H__ #include "socket.h" +#include "inspsocket.h" #include "dns.h" #include "mode.h" @@ -210,7 +211,7 @@ class User; * connection is stored here primarily, from the user's socket ID (file descriptor) through to the * user's nickname and hostname. */ -class CoreExport User : public EventHandler +class CoreExport User : public StreamSocket { private: /** A list of channels the user has a pending invite to. @@ -405,17 +406,6 @@ class CoreExport User : public EventHandler */ std::string password; - /** User's receive queue. - * Lines from the IRCd awaiting processing are stored here. - * Upgraded april 2005, old system a bit hairy. - */ - std::string recvq; - - /** User's send queue. - * Lines waiting to be sent are stored here until their buffer is flushed. - */ - std::string sendq; - /** Whether or not to send an snotice about this user's quitting */ bool quietquit; @@ -596,44 +586,6 @@ class CoreExport User : public EventHandler */ bool HasModePermission(unsigned char mode, ModeType type); - /** Calls read() to read some data for this user using their fd. - * @param buffer The buffer to read into - * @param size The size of data to read - * @return The number of bytes read, or -1 if an error occured. - */ - int ReadData(void* buffer, size_t size); - - /** This method adds data to the read buffer of the user. - * The buffer can grow to any size within limits of the available memory, - * managed by the size of a std::string, however if any individual line in - * the buffer grows over 600 bytes in length (which is 88 chars over the - * RFC-specified limit per line) then the method will return false and the - * text will not be inserted. - * @param a The string to add to the users read buffer - * @return True if the string was successfully added to the read buffer - */ - bool AddBuffer(const std::string &a); - - /** This method returns true if the buffer contains at least one carriage return - * character (e.g. one complete line may be read) - * @return True if there is at least one complete line in the users buffer - */ - bool BufferIsReady(); - - /** This function clears the entire buffer by setting it to an empty string. - */ - void ClearBuffer(); - - /** This method returns the first available string at the tail end of the buffer - * and advances the tail end of the buffer past the string. This means it is - * a one way operation in a similar way to strtok(), and multiple calls return - * multiple lines if they are available. The results of this function if there - * are no lines to be read are unknown, always use BufferIsReady() to check if - * it is ok to read the buffer before calling GetBuffer(). - * @return The string at the tail end of this users buffer - */ - std::string GetBuffer(); - /** Adds to the user's write buffer. * You may add any amount of text up to this users sendq value, if you exceed the * sendq value, the user will be removed, and further buffer adds will be dropped. @@ -641,14 +593,6 @@ class CoreExport User : public EventHandler */ void AddWriteBuf(const std::string &data); - /** Flushes as much of the user's buffer to the file descriptor as possible. - * This function may not always flush the entire buffer, rather instead as much of it - * as it possibly can. If the send() call fails to send the entire buffer, the buffer - * position is advanced forwards and the rest of the data sent at the next call to - * this method. - */ - void FlushWriteBuf(); - /** Returns the list of channels this user has been invited to but has not yet joined. * @return A list of channels the user is invited to */ @@ -672,12 +616,6 @@ class CoreExport User : public EventHandler */ const std::string& MakeHostIP(); - /** Shuts down and closes the user's socket - * This will not cause the user to be deleted. Use InspIRCd::QuitUser for this, - * which will call CloseSocket() for you. - */ - void CloseSocket(); - /** Add the user to WHOWAS system */ void AddToWhoWas(); @@ -911,16 +849,13 @@ class CoreExport User : public EventHandler */ void DecreasePenalty(int decrease); - /** Handle socket event. - * From EventHandler class. - * @param et Event type - * @param errornum Error number for EVENT_ERROR events - */ - void HandleEvent(EventType et, int errornum = 0); + void OnDataReady(); + void OnError(BufferedSocketError error); /** Default destructor */ virtual ~User(); + virtual void cull(); }; /** Derived from Resolver, and performs user forward/reverse lookups. diff --git a/src/base.cpp b/src/base.cpp index 27eb4af23..2b022688d 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -26,6 +26,14 @@ classbase::classbase() { } +void classbase::cull() +{ +} + +classbase::~classbase() +{ +} + void BoolSet::Set(int number) { this->bits |= bitfields[number]; diff --git a/src/command_parse.cpp b/src/command_parse.cpp index 92d4b8c24..cbf6a1005 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -226,23 +226,6 @@ CmdResult CommandParser::CallHandler(const std::string &commandname, const std:: return CMD_INVALID; } -void CommandParser::DoLines(User* current, bool one_only) -{ - while (current->BufferIsReady()) - { - // use GetBuffer to copy single lines into the sanitized string - std::string single_line = current->GetBuffer(); - current->bytes_in += single_line.length(); - current->cmds_in++; - if (single_line.length() > MAXBUF - 2) // MAXBUF is 514 to allow for neccessary line terminators - single_line.resize(MAXBUF - 2); // So to trim to 512 here, we use MAXBUF - 2 - - // ProcessBuffer returns false if the user has gone over penalty - if (!ServerInstance->Parser->ProcessBuffer(single_line, current) || one_only) - break; - } -} - bool CommandParser::ProcessCommand(User *user, std::string &cmd) { std::vector command_p; @@ -435,23 +418,12 @@ void CommandParser::RemoveCommand(Commandtable::iterator safei, Module* source) bool CommandParser::ProcessBuffer(std::string &buffer,User *user) { - std::string::size_type a; - - if (!user) + if (!user || buffer.empty()) return true; - while ((a = buffer.rfind("\n")) != std::string::npos) - buffer.erase(a); - while ((a = buffer.rfind("\r")) != std::string::npos) - buffer.erase(a); - - if (buffer.length()) - { - ServerInstance->Logs->Log("USERINPUT", DEBUG,"C[%d] I :%s %s",user->GetFd(), user->nick.c_str(), buffer.c_str()); - return this->ProcessCommand(user,buffer); - } - - return true; + ServerInstance->Logs->Log("USERINPUT", DEBUG, "C[%d] I :%s %s", + user->GetFd(), user->nick.c_str(), buffer.c_str()); + return ProcessCommand(user,buffer); } bool CommandParser::CreateCommand(Command *f) diff --git a/src/cull_list.cpp b/src/cull_list.cpp index 79c077ead..35fa44bfa 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -18,8 +18,12 @@ void CullList::Apply() { - for(std::vector::iterator i = list.begin(); i != list.end(); i++) - delete *i; + for(std::set::iterator i = list.begin(); i != list.end(); i++) + { + classbase* c = *i; + c->cull(); + delete c; + } list.clear(); } diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 0ec8db966..80feae464 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -125,20 +125,16 @@ void InspIRCd::SendError(const std::string &s) { for (std::vector::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++) { - if ((*i)->registered == REG_ALL) + User* u = *i; + if (u->registered == REG_ALL) { - (*i)->WriteServ("NOTICE %s :%s",(*i)->nick.c_str(),s.c_str()); + u->WriteServ("NOTICE %s :%s",u->nick.c_str(),s.c_str()); } else { /* Unregistered connections receive ERROR, not a NOTICE */ - (*i)->Write("ERROR :" + s); + u->Write("ERROR :" + s); } - /* This might generate a whole load of EAGAIN, but we dont really - * care about this, as if we call SendError something catastrophic - * has occured anyway, and we wont receive the events for these. - */ - (*i)->FlushWriteBuf(); } } diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 1b23bff02..704fec475 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -110,7 +110,6 @@ void InspIRCd::Cleanup() { User* u = *i++; Users->QuitUser(u, "Server shutdown"); - u->CloseSocket(); } /* We do this more than once, so that any service providers get a @@ -323,7 +322,6 @@ InspIRCd::InspIRCd(int argc, char** argv) : * THIS MUST MATCH ORDER OF DECLARATION OF THE HandleWhateverFunc classes * within class InspIRCd. */ - HandleProcessUser(this), HandleIsNick(this), HandleIsIdent(this), HandleFloodQuitUser(this), @@ -336,7 +334,6 @@ InspIRCd::InspIRCd(int argc, char** argv) : * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods * themselves within the class. */ - ProcessUser(&HandleProcessUser), IsChannel(&HandleIsChannel), IsSID(&HandleIsSID), Rehash(&HandleRehash), @@ -387,9 +384,8 @@ InspIRCd::InspIRCd(int argc, char** argv) : // This must be created first, so other parts of Insp can use it while starting up this->Logs = new LogManager(this); - SocketEngineFactory* SEF = new SocketEngineFactory(); - SE = SEF->Create(this); - delete SEF; + SocketEngineFactory SEF; + SE = SEF.Create(); this->Threads = new ThreadEngine(this); @@ -832,9 +828,6 @@ int InspIRCd::Run() /* if any users were quit, take them out */ this->GlobalCulls.Apply(); - /* If any inspsockets closed, remove them */ - this->BufferedSocketCull(); - if (this->s_signal) { this->SignalHandler(s_signal); @@ -845,18 +838,6 @@ int InspIRCd::Run() return 0; } -void InspIRCd::BufferedSocketCull() -{ - for (std::map::iterator x = SocketCull.begin(); x != SocketCull.end(); ++x) - { - this->Logs->Log("MISC",DEBUG,"Cull socket"); - SE->DelFd(x->second); - x->second->Close(); - delete x->second; - } - SocketCull.clear(); -} - /**********************************************************************************/ /** diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 0350858e7..964582062 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -16,195 +16,100 @@ #include "inspstring.h" #include "socketengine.h" -bool BufferedSocket::Readable() +BufferedSocket::BufferedSocket() { - return (this->state != I_CONNECTING); + Timeout = NULL; + state = I_ERROR; } -BufferedSocket::BufferedSocket(InspIRCd* SI) +BufferedSocket::BufferedSocket(int newfd) { - this->Timeout = NULL; - this->state = I_DISCONNECTED; - this->fd = -1; - this->ServerInstance = SI; -} - -BufferedSocket::BufferedSocket(InspIRCd* SI, int newfd, const char* ip) -{ - this->Timeout = NULL; + Timeout = NULL; this->fd = newfd; this->state = I_CONNECTED; - strlcpy(this->IP,ip,MAXBUF); - this->ServerInstance = SI; - if (this->fd > -1) - this->ServerInstance->SE->AddFd(this); + if (fd > -1) + ServerInstance->SE->AddFd(this); } -BufferedSocket::BufferedSocket(InspIRCd* SI, const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip) +void BufferedSocket::DoConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip) { - this->cbindip = connectbindip; - this->fd = -1; - this->ServerInstance = SI; - strlcpy(host,ipaddr.c_str(),MAXBUF); - this->Timeout = NULL; - - strlcpy(this->host,ipaddr.c_str(),MAXBUF); - this->port = aport; - - irc::sockets::sockaddrs testaddr; - if (!irc::sockets::aptosa(host, aport, &testaddr)) - { - this->ServerInstance->Logs->Log("SOCKET", DEBUG,"BUG: Hostname passed to BufferedSocket, rather than an IP address!"); - this->OnError(I_ERR_CONNECT); - this->Close(); - this->fd = -1; - this->state = I_ERROR; - return; - } - else + BufferedSocketError err = BeginConnect(ipaddr, aport, maxtime, connectbindip); + if (err != I_ERR_NONE) { - strlcpy(this->IP,host,MAXBUF); - if (!this->DoConnect(maxtime)) - { - this->OnError(I_ERR_CONNECT); - this->Close(); - this->fd = -1; - this->state = I_ERROR; - return; - } + state = I_ERROR; + SetError(strerror(errno)); + OnError(err); } } -void BufferedSocket::SetQueues() +BufferedSocketError BufferedSocket::BeginConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip) { - // attempt to increase socket sendq and recvq as high as its possible - int sendbuf = 32768; - int recvbuf = 32768; - if(setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf)) || setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf))) + irc::sockets::sockaddrs addr, bind; + if (!irc::sockets::aptosa(ipaddr.c_str(), aport, &addr)) { - //this->ServerInstance->Log(DEFAULT, "Could not increase SO_SNDBUF/SO_RCVBUF for socket %u", GetFd()); - ; // do nothing. I'm a little sick of people trying to interpret this message as a result of why their incorrect setups don't work. + ServerInstance->Logs->Log("SOCKET", DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!"); + return I_ERR_CONNECT; } -} -bool BufferedSocket::DoBindMagic(const std::string ¤t_ip) -{ - irc::sockets::sockaddrs s; - if (!irc::sockets::aptosa(current_ip.c_str(), 0, &s)) + bind.sa.sa_family = 0; + if (!connectbindip.empty()) { - errno = EADDRNOTAVAIL; - return false; - } - - if (ServerInstance->SE->Bind(this->fd, &s.sa, sa_size(s)) < 0) - { - this->state = I_ERROR; - this->OnError(I_ERR_BIND); - return false; + if (!irc::sockets::aptosa(connectbindip.c_str(), 0, &bind)) + { + return I_ERR_BIND; + } } - return true; + return BeginConnect(addr, bind, maxtime); } -/* Most irc servers require you to specify the ip you want to bind to. - * If you dont specify an IP, they rather dumbly bind to the first IP - * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP - * addresses we've bound server ports to, and we try and bind our outbound - * connections to the first usable non-loopback and non-any IP we find. - * This is easier to configure when you have a lot of links and a lot - * of servers to configure. - */ -bool BufferedSocket::BindAddr(const std::string &ip_to_bind) +static void IncreaseOSBuffers(int fd) { - ConfigReader Conf(this->ServerInstance); - - // Case one: If they provided an IP, try bind it - if (!ip_to_bind.empty()) - { - // And if it fails, don't do anything. - return this->DoBindMagic(ip_to_bind); - } - - for (int j = 0; j < Conf.Enumerate("bind"); j++) - { - // We only want to try bind to a server ip. - if (Conf.ReadValue("bind","type",j) != "servers") - continue; - - // set current IP to the tag - std::string current_ip = Conf.ReadValue("bind","address",j); - - // Make sure IP is nothing local - if (current_ip == "*" || current_ip == "127.0.0.1" || current_ip.empty() || current_ip == "::1") - continue; - - // Try bind, don't fail if it doesn't bind though. - if (this->DoBindMagic(current_ip)) - return true; - } - - // NOTE: You may wonder WTF we are returning *true* here, but that is because there were no custom binds setup, and so we have nothing to do - // (remember, outgoing connections without binding are perfectly ok). - ServerInstance->Logs->Log("SOCKET", DEBUG,"nothing in the config to bind()!"); - return true; + // attempt to increase socket sendq and recvq as high as its possible + int sendbuf = 32768; + int recvbuf = 32768; + setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf)); + setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(recvbuf)); + // on failure, do nothing. I'm a little sick of people trying to interpret this message as a result of why their incorrect setups don't work. } -bool BufferedSocket::DoConnect(unsigned long maxtime) +BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned long timeout) { - irc::sockets::sockaddrs addr; - irc::sockets::aptosa(this->host, this->port, &addr); - - this->fd = socket(addr.sa.sa_family, SOCK_STREAM, 0); + if (fd < 0) + fd = socket(dest.sa.sa_family, SOCK_STREAM, 0); - if (this->fd == -1) - { - this->state = I_ERROR; - this->OnError(I_ERR_SOCKET); - return false; - } + if (fd < 0) + return I_ERR_SOCKET; - if (!this->BindAddr(this->cbindip)) + if (bind.sa.sa_family != 0) { - this->Close(); - this->fd = -1; - return false; + if (ServerInstance->SE->Bind(fd, &bind.sa, sa_size(bind)) < 0) + return I_ERR_BIND; } - ServerInstance->SE->NonBlocking(this->fd); + ServerInstance->SE->NonBlocking(fd); - if (ServerInstance->SE->Connect(this, &addr.sa, sa_size(addr)) == -1) + if (ServerInstance->SE->Connect(this, &dest.sa, sa_size(dest)) == -1) { if (errno != EINPROGRESS) - { - this->OnError(I_ERR_CONNECT); - this->Close(); - this->state = I_ERROR; - return false; - } - - this->Timeout = new SocketTimeout(this->GetFd(), this->ServerInstance, this, maxtime, this->ServerInstance->Time()); - this->ServerInstance->Timers->AddTimer(this->Timeout); + return I_ERR_CONNECT; } this->state = I_CONNECTING; - if (this->fd > -1) - { - if (!this->ServerInstance->SE->AddFd(this)) - { - this->OnError(I_ERR_NOMOREFDS); - this->Close(); - this->state = I_ERROR; - return false; - } - this->SetQueues(); - } + + if (!ServerInstance->SE->AddFd(this, true)) + return I_ERR_NOMOREFDS; + + this->Timeout = new SocketTimeout(this->GetFd(), this, timeout, ServerInstance->Time()); + ServerInstance->Timers->AddTimer(this->Timeout); + + IncreaseOSBuffers(fd); ServerInstance->Logs->Log("SOCKET", DEBUG,"BufferedSocket::DoConnect success"); - return true; + return I_ERR_NONE; } - -void BufferedSocket::Close() +void StreamSocket::Close() { /* Save this, so we dont lose it, * otherise on failure, error messages @@ -213,190 +118,196 @@ void BufferedSocket::Close() int save = errno; if (this->fd > -1) { - if (this->GetIOHook()) + if (IOHook) { try { - this->GetIOHook()->OnRawSocketClose(this->fd); + IOHook->OnStreamSocketClose(this); } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + ServerInstance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", + modexcept.GetSource(), modexcept.GetReason()); } } ServerInstance->SE->Shutdown(this, 2); - if (ServerInstance->SE->Close(this) != -1) - this->OnClose(); - - if (ServerInstance->SocketCull.find(this) == ServerInstance->SocketCull.end()) - ServerInstance->SocketCull[this] = this; + ServerInstance->SE->DelFd(this); + ServerInstance->SE->Close(this); + fd = -1; } errno = save; } -std::string BufferedSocket::GetIP() +void StreamSocket::cull() { - return this->IP; + Close(); } -const char* BufferedSocket::Read() +bool StreamSocket::GetNextLine(std::string& line, char delim) { - if (!ServerInstance->SE->BoundsCheckFd(this)) - return NULL; - - int n = 0; - char* ReadBuffer = ServerInstance->GetReadBuffer(); + std::string::size_type i = recvq.find(delim); + if (i == std::string::npos) + return false; + line = recvq.substr(0, i - 1); + // TODO is this the most efficient way to split? + recvq = recvq.substr(i + 1); + return true; +} - if (this->GetIOHook()) +void StreamSocket::DoRead() +{ + if (IOHook) { - int result2 = 0; - int MOD_RESULT = 0; + int rv = -1; try { - MOD_RESULT = this->GetIOHook()->OnRawSocketRead(this->fd, ReadBuffer, ServerInstance->Config->NetBufferSize, result2); + rv = IOHook->OnStreamSocketRead(this, recvq); } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + ServerInstance->Logs->Log("SOCKET", DEFAULT, "%s threw an exception: %s", + modexcept.GetSource(), modexcept.GetReason()); + return; } - if (MOD_RESULT < 0) + if (rv > 0) + OnDataReady(); + if (rv < 0) + SetError("Read Error"); // will not overwrite a better error message + } + else + { + char* ReadBuffer = ServerInstance->GetReadBuffer(); + int n = recv(fd, ReadBuffer, ServerInstance->Config->NetBufferSize, 0); + if (n > 0) { - n = -1; - errno = EAGAIN; + recvq.append(ReadBuffer, n); + OnDataReady(); } - else + else if (n == 0) { - n = result2; + error = "Connection closed"; + } + else if (errno != EAGAIN && errno != EINTR) + { + error = strerror(errno); } - } - else - { - n = recv(this->fd, ReadBuffer, ServerInstance->Config->NetBufferSize, 0); - } - - /* - * This used to do some silly bounds checking instead of just passing bufsize - 1 to recv. - * Not only does that make absolutely no sense, but it could potentially result in a read buffer's worth - * of data being thrown into the bit bucket for no good reason, which is just *stupid*.. do things correctly now. - * --w00t (july 2, 2008) - */ - if (n > 0) - { - ReadBuffer[n] = 0; - return ReadBuffer; - } - else - { - int err = errno; - if (err == EAGAIN) - return ""; - else - return NULL; } } -/* - * This function formerly tried to flush write buffer each call. - * While admirable in attempting to get the data out to wherever - * it is going, on a full socket, it's just going to syscall write() and - * EAGAIN constantly, instead of waiting in the SE to know if it can write - * which will chew a bit of CPU. - * - * So, now this function returns void (take note) and just adds to the sendq. - * - * It'll get written at a determinate point when the socketengine tells us it can write. - * -- w00t (april 1, 2008) - */ -void BufferedSocket::Write(const std::string &data) +void StreamSocket::DoWrite() { - /* Append the data to the back of the queue ready for writing */ - outbuffer.push_back(data); - - /* Mark ourselves as wanting write */ - this->ServerInstance->SE->WantWrite(this); -} + if (sendq.empty()) + return; -bool BufferedSocket::FlushWriteBuffer() -{ - errno = 0; - if ((this->fd > -1) && (this->state == I_CONNECTED)) + if (IOHook) { - if (this->GetIOHook()) + int rv = -1; + try { - while (outbuffer.size() && (errno != EAGAIN)) + while (!sendq.empty()) { - try + std::string& front = sendq.front(); + int itemlen = front.length(); + rv = IOHook->OnStreamSocketWrite(this, front); + if (rv > 0) + { + // consumed the entire string, and is ready for more + sendq_len -= itemlen; + sendq.pop_front(); + } + else if (rv == 0) { - /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to - * implement their own buffering mechanisms - */ - this->GetIOHook()->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length()); - outbuffer.pop_front(); + // socket has blocked. Stop trying to send data. + // IOHook has requested unblock notification from the socketengine + + // Since it is possible that a partial write took place, adjust sendq_len + sendq_len = sendq_len - itemlen + front.length(); + return; } - catch (CoreException& modexcept) + else { - ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - return true; + SetError("Write Error"); // will not overwrite a better error message + return; } } } - else + catch (CoreException& modexcept) { - /* If we have multiple lines, try to send them all, - * not just the first one -- Brain - */ - while (outbuffer.size() && (errno != EAGAIN)) + ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", + modexcept.GetSource(), modexcept.GetReason()); + } + } + else + { + // Prepare a writev() call to write all buffers efficiently + int bufcount = sendq.size(); + + // cap the number of buffers at IOV_MAX + if (bufcount > IOV_MAX) + bufcount = IOV_MAX; + + iovec* iovecs = new iovec[bufcount]; + for(int i=0; i < bufcount; i++) + { + iovecs[i].iov_base = const_cast(sendq[i].data()); + iovecs[i].iov_len = sendq[i].length(); + } + int rv = writev(fd, iovecs, bufcount); + delete[] iovecs; + if (rv == (int)sendq_len) + { + // it's our lucky day, everything got written out. Fast cleanup. + sendq_len = 0; + sendq.clear(); + } + else if (rv > 0) + { + // Partial write. Clean out strings from the sendq + sendq_len -= rv; + while (rv > 0 && !sendq.empty()) { - /* Send a line */ - int result = ServerInstance->SE->Send(this, outbuffer[0].c_str(), outbuffer[0].length(), 0); - - if (result > 0) + std::string& front = sendq.front(); + if (front.length() < (size_t)rv) { - if ((unsigned int)result >= outbuffer[0].length()) - { - /* The whole block was written (usually a line) - * Pop the block off the front of the queue, - * dont set errno, because we are clear of errors - * and want to try and write the next block too. - */ - outbuffer.pop_front(); - } - else - { - std::string temp = outbuffer[0].substr(result); - outbuffer[0] = temp; - /* We didnt get the whole line out. arses. - * Try again next time, i guess. Set errno, - * because we shouldnt be writing any more now, - * until the socketengine says its safe to do so. - */ - errno = EAGAIN; - } + // this string got fully written out + rv -= front.length(); + sendq.pop_front(); } - else if (result == 0) + else { - this->ServerInstance->SE->DelFd(this); - this->Close(); - return true; - } - else if ((result == -1) && (errno != EAGAIN)) - { - this->OnError(I_ERR_WRITE); - this->state = I_ERROR; - this->ServerInstance->SE->DelFd(this); - this->Close(); - return true; + // stopped in the middle of this string + front = front.substr(rv); + rv = 0; } } } + else if (rv == 0) + { + error = "Connection closed"; + } + else if (errno != EAGAIN && errno != EINTR) + { + error = strerror(errno); + } + if (sendq_len && error.empty()) + ServerInstance->SE->WantWrite(this); } +} + +void StreamSocket::WriteData(const std::string &data) +{ + bool newWrite = sendq.empty() && !data.empty(); - if ((errno == EAGAIN) && (fd > -1)) + /* Append the data to the back of the queue ready for writing */ + sendq.push_back(data); + sendq_len += data.length(); + + if (newWrite) { - this->ServerInstance->SE->WantWrite(this); + // TODO perhaps we should try writing first, before asking SE about writes? + // DoWrite(); + ServerInstance->SE->WantWrite(this); } - - return (fd < 0); } void SocketTimeout::Tick(time_t) @@ -421,57 +332,26 @@ void SocketTimeout::Tick(time_t) */ this->sock->state = I_ERROR; - if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end()) - ServerInstance->SocketCull[this->sock] = this->sock; + ServerInstance->GlobalCulls.AddItem(sock); } this->sock->Timeout = NULL; } -bool BufferedSocket::InternalMarkConnected() -{ - /* Our socket was in write-state, so delete it and re-add it - * in read-state. - */ - this->SetState(I_CONNECTED); +void BufferedSocket::OnConnected() { } +void BufferedSocket::OnTimeout() { return; } - if (this->GetIOHook()) +void BufferedSocket::DoWrite() +{ + if (state == I_CONNECTING) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Hook for raw connect"); - try - { - this->GetIOHook()->OnRawSocketConnect(this->fd); - } - catch (CoreException& modexcept) - { - ServerInstance->Logs->Log("SOCKET",DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - return false; - } + state = I_CONNECTED; + this->OnConnected(); + if (GetIOHook()) + GetIOHook()->OnStreamSocketConnect(this); } - return this->OnConnected(); -} - -void BufferedSocket::SetState(BufferedSocketState s) -{ - this->state = s; -} - -BufferedSocketState BufferedSocket::GetState() -{ - return this->state; -} - -bool BufferedSocket::OnConnected() { return true; } -void BufferedSocket::OnError(BufferedSocketError) { return; } -int BufferedSocket::OnDisconnect() { return 0; } -bool BufferedSocket::OnDataReady() { return true; } -bool BufferedSocket::OnWriteReady() -{ - // Default behaviour: just try write some. - return !this->FlushWriteBuffer(); + this->StreamSocket::DoWrite(); } -void BufferedSocket::OnTimeout() { return; } -void BufferedSocket::OnClose() { return; } BufferedSocket::~BufferedSocket() { @@ -483,68 +363,49 @@ BufferedSocket::~BufferedSocket() } } -void BufferedSocket::HandleEvent(EventType et, int errornum) +void StreamSocket::HandleEvent(EventType et, int errornum) { + BufferedSocketError errcode = I_ERR_OTHER; switch (et) { case EVENT_ERROR: { + SetError(strerror(errornum)); switch (errornum) { case ETIMEDOUT: - this->OnError(I_ERR_TIMEOUT); + errcode = I_ERR_TIMEOUT; break; case ECONNREFUSED: case 0: - this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE); + errcode = I_ERR_CONNECT; break; case EADDRINUSE: - this->OnError(I_ERR_BIND); + errcode = I_ERR_BIND; break; case EPIPE: case EIO: - this->OnError(I_ERR_WRITE); + errcode = I_ERR_WRITE; break; } - - if (this->ServerInstance->SocketCull.find(this) == this->ServerInstance->SocketCull.end()) - this->ServerInstance->SocketCull[this] = this; - return; break; } case EVENT_READ: { - if (!this->OnDataReady()) - { - if (this->ServerInstance->SocketCull.find(this) == this->ServerInstance->SocketCull.end()) - this->ServerInstance->SocketCull[this] = this; - return; - } + DoRead(); break; } case EVENT_WRITE: { - if (this->state == I_CONNECTING) - { - if (!this->InternalMarkConnected()) - { - if (this->ServerInstance->SocketCull.find(this) == this->ServerInstance->SocketCull.end()) - this->ServerInstance->SocketCull[this] = this; - return; - } - return; - } - else - { - if (!this->OnWriteReady()) - { - if (this->ServerInstance->SocketCull.find(this) == this->ServerInstance->SocketCull.end()) - this->ServerInstance->SocketCull[this] = this; - return; - } - } + DoWrite(); break; } } + if (!error.empty()) + { + ServerInstance->Logs->Log("SOCKET", DEBUG, "Error on FD %d - '%s'", fd, error.c_str()); + OnError(errcode); + ServerInstance->GlobalCulls.AddItem(this); + } } diff --git a/src/modules.cpp b/src/modules.cpp index 51fecb47c..c11b63bec 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -159,11 +159,11 @@ void Module::OnGlobalOper(User*) { } void Module::OnPostConnect(User*) { } ModResult Module::OnAddBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; } ModResult Module::OnDelBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; } -void Module::OnRawSocketAccept(int, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { } -int Module::OnRawSocketWrite(int, const char*, int) { return 0; } -void Module::OnRawSocketClose(int) { } -void Module::OnRawSocketConnect(int) { } -int Module::OnRawSocketRead(int, char*, unsigned int, int&) { return 0; } +void Module::OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { } +int Module::OnStreamSocketWrite(StreamSocket*, std::string&) { return -1; } +void Module::OnStreamSocketClose(StreamSocket*) { } +void Module::OnStreamSocketConnect(StreamSocket*) { } +int Module::OnStreamSocketRead(StreamSocket*, std::string&) { return -1; } void Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&) { } void Module::OnUserNotice(User*, void*, int, const std::string&, char, const CUList&) { } void Module::OnRemoteKill(User*, User*, const std::string&, const std::string&) { } @@ -196,7 +196,7 @@ void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { } void Module::OnRunTestSuite() { } void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { } ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnHookIO(EventHandler*, ListenSocketBase*) { } +void Module::OnHookIO(StreamSocket*, ListenSocketBase*) { } ModResult Module::OnHostCycle(User*) { return MOD_RES_PASSTHRU; } void Module::OnSendWhoLine(User*, User*, Channel*, std::string&) { } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index f458f5da1..27c466573 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -56,7 +56,6 @@ public: gnutls_session_t sess; issl_status status; - std::string outbuf; }; class CommandStartTLS : public Command @@ -83,7 +82,7 @@ class CommandStartTLS : public Command { user->WriteNumeric(670, "%s :STARTTLS successful, go ahead with TLS handshake", user->nick.c_str()); user->AddIOHook(creator); - creator->OnRawSocketAccept(user->GetFd(), NULL, NULL); + creator->OnStreamSocketAccept(user, NULL, NULL); } else user->WriteNumeric(691, "%s :STARTTLS failure", user->nick.c_str()); @@ -133,16 +132,14 @@ class ModuleSSLGnuTLS : public Module // Void return, guess we assume success gnutls_certificate_set_dh_params(x509_cred, dh_params); - Implementation eventlist[] = { I_On005Numeric, I_OnRawSocketConnect, I_OnRawSocketAccept, - I_OnRawSocketClose, I_OnRawSocketRead, I_OnRawSocketWrite, I_OnCleanup, - I_OnBufferFlushed, I_OnRequest, I_OnRehash, I_OnModuleRehash, I_OnPostConnect, + Implementation eventlist[] = { I_On005Numeric, I_OnRequest, I_OnRehash, I_OnModuleRehash, I_OnPostConnect, I_OnEvent, I_OnHookIO }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServerInstance->AddCommand(&starttls); } - virtual void OnRehash(User* user) + void OnRehash(User* user) { ConfigReader Conf(ServerInstance); @@ -168,7 +165,7 @@ class ModuleSSLGnuTLS : public Module sslports.erase(sslports.end() - 1); } - virtual void OnModuleRehash(User* user, const std::string ¶m) + void OnModuleRehash(User* user, const std::string ¶m) { if(param != "ssl") return; @@ -278,7 +275,7 @@ class ModuleSSLGnuTLS : public Module ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret)); } - virtual ~ModuleSSLGnuTLS() + ~ModuleSSLGnuTLS() { gnutls_x509_crt_deinit(x509_cert); gnutls_x509_privkey_deinit(x509_key); @@ -289,7 +286,7 @@ class ModuleSSLGnuTLS : public Module delete[] sessions; } - virtual void OnCleanup(int target_type, void* item) + void OnCleanup(int target_type, void* item) { if(target_type == TYPE_USER) { @@ -305,20 +302,20 @@ class ModuleSSLGnuTLS : public Module } } - virtual Version GetVersion() + Version GetVersion() { return Version("$Id$", VF_VENDOR, API_VERSION); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::string &output) { if (!sslports.empty()) output.append(" SSL=" + sslports); output.append(" STARTTLS"); } - virtual void OnHookIO(EventHandler* user, ListenSocketBase* lsb) + void OnHookIO(StreamSocket* user, ListenSocketBase* lsb) { if (!user->GetIOHook() && listenports.find(lsb) != listenports.end()) { @@ -327,7 +324,7 @@ class ModuleSSLGnuTLS : public Module } } - virtual const char* OnRequest(Request* request) + const char* OnRequest(Request* request) { ISHRequest* ISR = static_cast(request); if (strcmp("IS_NAME", request->GetId()) == 0) @@ -336,20 +333,13 @@ class ModuleSSLGnuTLS : public Module } else if (strcmp("IS_HOOK", request->GetId()) == 0) { - const char* ret = "OK"; - try - { - ret = ISR->Sock->AddIOHook(this) ? "OK" : NULL; - } - catch (ModuleException &e) - { - return NULL; - } - return ret; + ISR->Sock->AddIOHook(this); + return "OK"; } else if (strcmp("IS_UNHOOK", request->GetId()) == 0) { - return ISR->Sock->DelIOHook() ? "OK" : NULL; + ISR->Sock->DelIOHook(); + return "OK"; } else if (strcmp("IS_HSDONE", request->GetId()) == 0) { @@ -383,12 +373,9 @@ class ModuleSSLGnuTLS : public Module } - virtual void OnRawSocketAccept(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return; - + int fd = user->GetFd(); issl_session* session = &sessions[fd]; /* For STARTTLS: Don't try and init a session on a socket that already has a session */ @@ -405,77 +392,67 @@ class ModuleSSLGnuTLS : public Module gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. - Handshake(session, fd); + Handshake(session, user); } - virtual void OnRawSocketConnect(int fd) + void OnStreamSocketConnect(StreamSocket* user) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return; - - issl_session* session = &sessions[fd]; + issl_session* session = &sessions[user->GetFd()]; gnutls_init(&session->sess, GNUTLS_CLIENT); gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast(fd)); // Give gnutls the fd for the socket. + gnutls_transport_set_ptr(session->sess, reinterpret_cast(user->GetFd())); - Handshake(session, fd); + Handshake(session, user); } - virtual void OnRawSocketClose(int fd) + void OnStreamSocketClose(StreamSocket* user) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds())) - return; - - CloseSession(&sessions[fd]); + CloseSession(&sessions[user->GetFd()]); } - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) + int OnStreamSocketRead(StreamSocket* user, std::string& recvq) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return 0; - - issl_session* session = &sessions[fd]; + issl_session* session = &sessions[user->GetFd()]; if (!session->sess) { - readresult = 0; CloseSession(session); - return 1; + user->SetError("No SSL session"); + return -1; } if (session->status == ISSL_HANDSHAKING_READ) { // The handshake isn't finished, try to finish it. - if(!Handshake(session, fd)) + if(!Handshake(session, user)) { - errno = session->status == ISSL_CLOSING ? EIO : EAGAIN; - // Couldn't resume handshake. + if (session->status != ISSL_CLOSING) + return 0; + user->SetError("Handshake Failed"); return -1; } } else if (session->status == ISSL_HANDSHAKING_WRITE) { - errno = EAGAIN; - MakePollWrite(fd); - return -1; + MakePollWrite(user); + return 0; } // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN. if (session->status == ISSL_HANDSHAKEN) { - unsigned int len = 0; - while (len < count) + char* buffer = ServerInstance->GetReadBuffer(); + size_t bufsiz = ServerInstance->Config->NetBufferSize; + size_t len = 0; + while (len < bufsiz) { - int ret = gnutls_record_recv(session->sess, buffer + len, count - len); + int ret = gnutls_record_recv(session->sess, buffer + len, bufsiz - len); if (ret > 0) { len += ret; @@ -484,60 +461,49 @@ class ModuleSSLGnuTLS : public Module { break; } + else if (ret == 0) + { + user->SetError("SSL Connection closed"); + CloseSession(session); + return -1; + } else { - if (ret != 0) - ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, - "m_ssl_gnutls.so: Error while reading on fd %d: %s", - fd, gnutls_strerror(ret)); - - // if ret == 0, client closed connection. - readresult = 0; + user->SetError(gnutls_strerror(ret)); CloseSession(session); - return 1; + return -1; } } - readresult = len; if (len) { + recvq.append(buffer, len); return 1; } - else - { - errno = EAGAIN; - return -1; - } } else if (session->status == ISSL_CLOSING) - readresult = 0; + return -1; - return 1; + return 0; } - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) + int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return 0; - - issl_session* session = &sessions[fd]; - const char* sendbuffer = buffer; + issl_session* session = &sessions[user->GetFd()]; if (!session->sess) { CloseSession(session); - return 1; + user->SetError("No SSL session"); + return -1; } - session->outbuf.append(sendbuffer, count); - sendbuffer = session->outbuf.c_str(); - count = session->outbuf.size(); - if (session->status == ISSL_HANDSHAKING_WRITE || session->status == ISSL_HANDSHAKING_READ) { // The handshake isn't finished, try to finish it. - Handshake(session, fd); - errno = session->status == ISSL_CLOSING ? EIO : EAGAIN; + Handshake(session, user); + if (session->status != ISSL_CLOSING) + return 0; + user->SetError("Handshake Failed"); return -1; } @@ -545,42 +511,41 @@ class ModuleSSLGnuTLS : public Module if (session->status == ISSL_HANDSHAKEN) { - ret = gnutls_record_send(session->sess, sendbuffer, count); + ret = gnutls_record_send(session->sess, sendq.data(), sendq.length()); - if (ret == 0) + if (ret == (int)sendq.length()) { - CloseSession(session); + return 1; } - else if (ret < 0) + else if (ret > 0) { - if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED) - { - ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, - "m_ssl_gnutls.so: Error while writing to fd %d: %s", - fd, gnutls_strerror(ret)); - CloseSession(session); - } - else - { - errno = EAGAIN; - } + sendq = sendq.substr(ret); + MakePollWrite(user); + return 0; } - else + else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) + { + MakePollWrite(user); + return 0; + } + else if (ret == 0) { - session->outbuf = session->outbuf.substr(ret); + CloseSession(session); + user->SetError("SSL Connection closed"); + return -1; + } + else // (ret < 0) + { + user->SetError(gnutls_strerror(ret)); + CloseSession(session); + return -1; } } - if (!session->outbuf.empty()) - MakePollWrite(fd); - - /* Who's smart idea was it to return 1 when we havent written anything? - * This fucks the buffer up in BufferedSocket :p - */ - return ret < 1 ? 0 : ret; + return 0; } - bool Handshake(issl_session* session, int fd) + bool Handshake(issl_session* session, EventHandler* user) { int ret = gnutls_handshake(session->sess); @@ -599,15 +564,11 @@ class ModuleSSLGnuTLS : public Module { // gnutls_handshake() wants to write() again. session->status = ISSL_HANDSHAKING_WRITE; - MakePollWrite(fd); + MakePollWrite(user); } } else { - // Handshake failed. - ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, - "m_ssl_gnutls.so: Handshake failed on fd %d: %s", - fd, gnutls_strerror(ret)); CloseSession(session); session->status = ISSL_CLOSING; } @@ -619,18 +580,16 @@ class ModuleSSLGnuTLS : public Module // Change the seesion state session->status = ISSL_HANDSHAKEN; - EventHandler* user = ServerInstance->SE->GetRef(fd); - VerifyCertificate(session,user); // Finish writing, if any left - MakePollWrite(fd); + MakePollWrite(user); return true; } } - virtual void OnPostConnect(User* user) + void OnPostConnect(User* user) { // This occurs AFTER OnUserConnect so we can be sure the // protocol module has propagated the NICK message. @@ -646,22 +605,9 @@ class ModuleSSLGnuTLS : public Module } } - void MakePollWrite(int fd) + void MakePollWrite(EventHandler* eh) { - //OnRawSocketWrite(fd, NULL, 0); - EventHandler* eh = ServerInstance->SE->GetRef(fd); - if (eh) - ServerInstance->SE->WantWrite(eh); - } - - virtual void OnBufferFlushed(User* user) - { - if (user->GetIOHook() == this) - { - issl_session* session = &sessions[user->GetFd()]; - if (session && session->outbuf.size()) - OnRawSocketWrite(user->GetFd(), NULL, 0); - } + ServerInstance->SE->WantWrite(eh); } void CloseSession(issl_session* session) @@ -672,7 +618,6 @@ class ModuleSSLGnuTLS : public Module gnutls_deinit(session->sess); } - session->outbuf.clear(); session->sess = NULL; session->status = ISSL_NONE; } diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index a33cf6bc2..e77fa23ff 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -59,7 +59,7 @@ public: unsigned int inbufoffset; char* inbuf; // Buffer OpenSSL reads into. - std::string outbuf; // Buffer for outgoing data that OpenSSL will not take. + std::string outbuf; int fd; bool outbound; @@ -95,7 +95,6 @@ class ModuleSSLOpenSSL : public Module SSL_CTX* ctx; SSL_CTX* clictx; - char* dummy; char cipher[MAXBUF]; std::string keyfile; @@ -137,14 +136,13 @@ class ModuleSSLOpenSSL : public Module // Needs the flag as it ignores a plain /rehash OnModuleRehash(NULL,"ssl"); - Implementation eventlist[] = { I_OnRawSocketConnect, I_OnRawSocketAccept, - I_OnRawSocketClose, I_OnRawSocketRead, I_OnRawSocketWrite, I_OnCleanup, I_On005Numeric, - I_OnBufferFlushed, I_OnRequest, I_OnRehash, I_OnModuleRehash, I_OnPostConnect, + Implementation eventlist[] = { + I_On005Numeric, I_OnBufferFlushed, I_OnRequest, I_OnRehash, I_OnModuleRehash, I_OnPostConnect, I_OnHookIO }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnHookIO(EventHandler* user, ListenSocketBase* lsb) + void OnHookIO(StreamSocket* user, ListenSocketBase* lsb) { if (!user->GetIOHook() && listenports.find(lsb) != listenports.end()) { @@ -153,7 +151,7 @@ class ModuleSSLOpenSSL : public Module } } - virtual void OnRehash(User* user) + void OnRehash(User* user) { ConfigReader Conf(ServerInstance); @@ -179,7 +177,7 @@ class ModuleSSLOpenSSL : public Module sslports.erase(sslports.end() - 1); } - virtual void OnModuleRehash(User* user, const std::string ¶m) + void OnModuleRehash(User* user, const std::string ¶m) { if (param != "ssl") return; @@ -266,13 +264,13 @@ class ModuleSSLOpenSSL : public Module fclose(dhpfile); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::string &output) { if (!sslports.empty()) output.append(" SSL=" + sslports); } - virtual ~ModuleSSLOpenSSL() + ~ModuleSSLOpenSSL() { SSL_CTX_free(ctx); SSL_CTX_free(clictx); @@ -280,7 +278,7 @@ class ModuleSSLOpenSSL : public Module delete[] sessions; } - virtual void OnCleanup(int target_type, void* item) + void OnCleanup(int target_type, void* item) { if (target_type == TYPE_USER) { @@ -296,13 +294,13 @@ class ModuleSSLOpenSSL : public Module } } - virtual Version GetVersion() + Version GetVersion() { return Version("$Id$", VF_VENDOR, API_VERSION); } - virtual const char* OnRequest(Request* request) + const char* OnRequest(Request* request) { ISHRequest* ISR = (ISHRequest*)request; if (strcmp("IS_NAME", request->GetId()) == 0) @@ -311,21 +309,13 @@ class ModuleSSLOpenSSL : public Module } else if (strcmp("IS_HOOK", request->GetId()) == 0) { - const char* ret = "OK"; - try - { - ret = ISR->Sock->AddIOHook((Module*)this) ? "OK" : NULL; - } - catch (ModuleException &e) - { - return NULL; - } - - return ret; + ISR->Sock->AddIOHook(this); + return "OK"; } else if (strcmp("IS_UNHOOK", request->GetId()) == 0) { - return ISR->Sock->DelIOHook() ? "OK" : NULL; + ISR->Sock->DelIOHook(); + return "OK"; } else if (strcmp("IS_HSDONE", request->GetId()) == 0) { @@ -353,11 +343,9 @@ class ModuleSSLOpenSSL : public Module } - virtual void OnRawSocketAccept(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { - /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return; + int fd = user->GetFd(); issl_session* session = &sessions[fd]; @@ -377,11 +365,12 @@ class ModuleSSLOpenSSL : public Module return; } - Handshake(session); + Handshake(user, session); } - virtual void OnRawSocketConnect(int fd) + void OnStreamSocketConnect(StreamSocket* user) { + int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() -1)) return; @@ -404,11 +393,12 @@ class ModuleSSLOpenSSL : public Module return; } - Handshake(session); + Handshake(user, session); } - virtual void OnRawSocketClose(int fd) + void OnStreamSocketClose(StreamSocket* user) { + int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) return; @@ -416,19 +406,19 @@ class ModuleSSLOpenSSL : public Module CloseSession(&sessions[fd]); } - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) + int OnStreamSocketRead(StreamSocket* user, std::string& recvq) { + int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return 0; + return -1; issl_session* session = &sessions[fd]; if (!session->sess) { - readresult = 0; CloseSession(session); - return 1; + return -1; } if (session->status == ISSL_HANDSHAKING) @@ -436,17 +426,17 @@ class ModuleSSLOpenSSL : public Module if (session->rstat == ISSL_READ || session->wstat == ISSL_READ) { // The handshake isn't finished and it wants to read, try to finish it. - if (!Handshake(session)) + if (!Handshake(user, session)) { // Couldn't resume handshake. - errno = session->status == ISSL_NONE ? EIO : EAGAIN; - return -1; + if (session->status == ISSL_NONE) + return -1; + return 0; } } else { - errno = EAGAIN; - return -1; + return 0; } } @@ -456,51 +446,37 @@ class ModuleSSLOpenSSL : public Module { if (session->wstat == ISSL_READ) { - if(DoWrite(session) == 0) + if(DoWrite(user, session) == 0) return 0; } if (session->rstat == ISSL_READ) { - int ret = DoRead(session); + int ret = DoRead(user, session); if (ret > 0) { - if (count <= session->inbufoffset) - { - memcpy(buffer, session->inbuf, count); - // Move the stuff left in inbuf to the beginning of it - memmove(session->inbuf, session->inbuf + count, (session->inbufoffset - count)); - // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp. - session->inbufoffset -= count; - // Insp uses readresult as the count of how much data there is in buffer, so: - readresult = count; - } - else - { - // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing. - memcpy(buffer, session->inbuf, session->inbufoffset); - - readresult = session->inbufoffset; - // Zero the offset, as there's nothing there.. - session->inbufoffset = 0; - } + recvq.append(session->inbuf, session->inbufoffset); + session->inbufoffset = 0; return 1; } - return ret; + else if (errno == EAGAIN || errno == EINTR) + return 0; + else + return -1; } } - return -1; + return 0; } - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) + int OnStreamSocketWrite(StreamSocket* user, std::string& buffer) { + int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return 0; + return -1; - errno = EAGAIN; issl_session* session = &sessions[fd]; if (!session->sess) @@ -509,40 +485,53 @@ class ModuleSSLOpenSSL : public Module return -1; } - session->outbuf.append(buffer, count); - MakePollWrite(session); - if (session->status == ISSL_HANDSHAKING) { // The handshake isn't finished, try to finish it. if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE) { - if (!Handshake(session)) + if (!Handshake(user, session)) { // Couldn't resume handshake. - errno = session->status == ISSL_NONE ? EIO : EAGAIN; - return -1; + if (session->status == ISSL_NONE) + return -1; + return 0; } } } + int rv = 0; + + // don't pull items into the output buffer until they are + // unlikely to block; this allows sendq exceeded to continue + // to work for SSL users. + // TODO better signaling for I/O requests so this isn't needed + if (session->outbuf.empty()) + { + session->outbuf = buffer; + rv = 1; + } + if (session->status == ISSL_OPEN) { if (session->rstat == ISSL_WRITE) { - DoRead(session); + DoRead(user, session); } if (session->wstat == ISSL_WRITE) { - return DoWrite(session); + DoWrite(user, session); } } - return 1; + if (rv == 0 || !session->outbuf.empty()) + ServerInstance->SE->WantWrite(user); + + return rv; } - int DoWrite(issl_session* session) + int DoWrite(StreamSocket* user, issl_session* session) { if (!session->outbuf.size()) return -1; @@ -561,6 +550,7 @@ class ModuleSSLOpenSSL : public Module if (err == SSL_ERROR_WANT_WRITE) { session->wstat = ISSL_WRITE; + ServerInstance->SE->WantWrite(user); return -1; } else if (err == SSL_ERROR_WANT_READ) @@ -581,7 +571,7 @@ class ModuleSSLOpenSSL : public Module } } - int DoRead(issl_session* session) + int DoRead(StreamSocket* user, issl_session* session) { // Is this right? Not sure if the unencrypted data is garaunteed to be the same length. // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet. @@ -606,7 +596,7 @@ class ModuleSSLOpenSSL : public Module else if (err == SSL_ERROR_WANT_WRITE) { session->rstat = ISSL_WRITE; - MakePollWrite(session); + ServerInstance->SE->WantWrite(user); return -1; } else @@ -627,7 +617,7 @@ class ModuleSSLOpenSSL : public Module } } - bool Handshake(issl_session* session) + bool Handshake(EventHandler* user, issl_session* session) { int ret; @@ -650,7 +640,7 @@ class ModuleSSLOpenSSL : public Module { session->wstat = ISSL_WRITE; session->status = ISSL_HANDSHAKING; - MakePollWrite(session); + ServerInstance->SE->WantWrite(user); return true; } else @@ -669,7 +659,7 @@ class ModuleSSLOpenSSL : public Module session->status = ISSL_OPEN; - MakePollWrite(session); + ServerInstance->SE->WantWrite(user); return true; } @@ -682,34 +672,14 @@ class ModuleSSLOpenSSL : public Module return true; } - virtual void OnPostConnect(User* user) - { - // This occurs AFTER OnUserConnect so we can be sure the - // protocol module has propagated the NICK message. - if ((user->GetIOHook() == this) && (IS_LOCAL(user))) - { - if (sessions[user->GetFd()].sess) - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->GetFd()].sess)); - } - } - - void MakePollWrite(issl_session* session) - { - //OnRawSocketWrite(session->fd, NULL, 0); - EventHandler* eh = ServerInstance->SE->GetRef(session->fd); - if (eh) - { - ServerInstance->SE->WantWrite(eh); - } - } - - virtual void OnBufferFlushed(User* user) + void OnBufferFlushed(User* user) { if (user->GetIOHook() == this) { + std::string dummy; issl_session* session = &sessions[user->GetFd()]; if (session && session->outbuf.size()) - OnRawSocketWrite(user->GetFd(), NULL, 0); + OnStreamSocketWrite(user, dummy); } } diff --git a/src/modules/extra/m_ziplink.cpp b/src/modules/extra/m_ziplink.cpp index c220460bd..7d090d80a 100644 --- a/src/modules/extra/m_ziplink.cpp +++ b/src/modules/extra/m_ziplink.cpp @@ -67,29 +67,29 @@ class ModuleZLib : public Module total_out_compressed = total_in_compressed = 0; total_out_uncompressed = total_in_uncompressed = 0; - Implementation eventlist[] = { I_OnRawSocketConnect, I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketRead, I_OnRawSocketWrite, I_OnStats, I_OnRequest }; - ServerInstance->Modules->Attach(eventlist, this, 7); + Implementation eventlist[] = { I_OnStats, I_OnRequest }; + ServerInstance->Modules->Attach(eventlist, this, 2); // Allocate a buffer which is used for reading and writing data net_buffer_size = ServerInstance->Config->NetBufferSize; net_buffer = new char[net_buffer_size]; } - virtual ~ModuleZLib() + ~ModuleZLib() { ServerInstance->Modules->UnpublishInterface("BufferedSocketHook", this); delete[] sessions; delete[] net_buffer; } - virtual Version GetVersion() + Version GetVersion() { return Version("$Id$", VF_VENDOR, API_VERSION); } /* Handle BufferedSocketHook API requests */ - virtual const char* OnRequest(Request* request) + const char* OnRequest(Request* request) { ISHRequest* ISR = (ISHRequest*)request; if (strcmp("IS_NAME", request->GetId()) == 0) @@ -99,22 +99,13 @@ class ModuleZLib : public Module } else if (strcmp("IS_HOOK", request->GetId()) == 0) { - /* Attach to an inspsocket */ - const char* ret = "OK"; - try - { - ret = ISR->Sock->AddIOHook((Module*)this) ? "OK" : NULL; - } - catch (ModuleException& e) - { - return NULL; - } - return ret; + ISR->Sock->AddIOHook(this); + return "OK"; } else if (strcmp("IS_UNHOOK", request->GetId()) == 0) { - /* Detach from an inspsocket */ - return ISR->Sock->DelIOHook() ? "OK" : NULL; + ISR->Sock->DelIOHook(); + return "OK"; } else if (strcmp("IS_HSDONE", request->GetId()) == 0) { @@ -134,7 +125,7 @@ class ModuleZLib : public Module } /* Handle stats z (misc stats) */ - virtual ModResult OnStats(char symbol, User* user, string_list &results) + ModResult OnStats(char symbol, User* user, string_list &results) { if (symbol == 'z') { @@ -174,10 +165,14 @@ class ModuleZLib : public Module return MOD_RES_PASSTHRU; } - virtual void OnRawSocketConnect(int fd) + void OnStreamSocketConnect(StreamSocket* user) { - if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1)) - return; + OnStreamSocketAccept(user, 0, 0); + } + + void OnRawSocketAccept(StreamSocket* user, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) + { + int fd = user->GetFd(); izip_session* session = &sessions[fd]; @@ -211,39 +206,33 @@ class ModuleZLib : public Module session->status = IZIP_OPEN; } - virtual void OnRawSocketAccept(int fd, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) - { - /* Nothing special needs doing here compared to connect() */ - OnRawSocketConnect(fd); - } - - virtual void OnRawSocketClose(int fd) + void OnStreamSocketClose(StreamSocket* user) { + int fd = user->GetFd(); CloseSession(&sessions[fd]); } - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) + int OnStreamSocketRead(StreamSocket* user, std::string& recvq) { + int fd = user->GetFd(); /* Find the sockets session */ izip_session* session = &sessions[fd]; if (session->status == IZIP_CLOSED) - return 0; + return -1; - if (session->inbuf.length()) - { - /* Our input buffer is filling up. This is *BAD*. - * We can't return more data than fits into buffer - * (count bytes), so we will generate another read - * event on purpose by *NOT* reading from 'fd' at all - * for now. - */ - readresult = 0; - } - else + if (session->inbuf.empty()) { /* Read read_buffer_size bytes at a time to the buffer (usually 2.5k) */ - readresult = read(fd, net_buffer, net_buffer_size); + int readresult = read(fd, net_buffer, net_buffer_size); + + if (readresult < 0) + { + if (errno == EINTR || errno == EAGAIN) + return 0; + } + if (readresult <= 0) + return -1; total_in_compressed += readresult; @@ -252,10 +241,8 @@ class ModuleZLib : public Module } size_t in_len = session->inbuf.length(); - - /* Do we have anything to do? */ - if (in_len <= 0) - return 0; + char* buffer = ServerInstance->GetReadBuffer(); + int count = ServerInstance->Config->NetBufferSize; /* Prepare decompression */ session->d_stream.next_in = (Bytef *)session->inbuf.c_str(); @@ -302,8 +289,7 @@ class ModuleZLib : public Module } if (ret != Z_OK) { - readresult = 0; - return 0; + return -1; } /* Update the inbut buffer */ @@ -315,24 +301,18 @@ class ModuleZLib : public Module total_in_uncompressed += uncompressed_length; /* Null-terminate the buffer -- this doesnt harm binary data */ - buffer[uncompressed_length] = 0; - - /* Set the read size to the correct total size */ - readresult = uncompressed_length; - + recvq.append(buffer, uncompressed_length); return 1; } - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) + int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) { + int fd = user->GetFd(); izip_session* session = &sessions[fd]; - if (!count) /* Nothing to do! */ - return 0; - if(session->status != IZIP_OPEN) /* Seriously, wtf? */ - return 0; + return -1; int ret; @@ -343,8 +323,8 @@ class ModuleZLib : public Module do { /* Prepare compression */ - session->c_stream.next_in = (Bytef*)buffer + offset; - session->c_stream.avail_in = count - offset; + session->c_stream.next_in = (Bytef*)sendq.data() + offset; + session->c_stream.avail_in = sendq.length() - offset; session->c_stream.next_out = (Bytef*)net_buffer; session->c_stream.avail_out = net_buffer_size; @@ -378,7 +358,7 @@ class ModuleZLib : public Module /* Space before - space after stuff was added to this */ unsigned int compressed = net_buffer_size - session->c_stream.avail_out; - unsigned int uncompressed = count - session->c_stream.avail_in; + unsigned int uncompressed = sendq.length() - session->c_stream.avail_in; /* Make it skip the data which was compressed already */ offset += uncompressed; @@ -404,14 +384,11 @@ class ModuleZLib : public Module else { session->outbuf.clear(); - return 0; + return -1; } } - /* ALL LIES the lot of it, we havent really written - * this amount, but the layer above doesnt need to know. - */ - return count; + return 1; } void Error(izip_session* session, const std::string &text) diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index bdf4e424e..c1698accf 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -37,6 +37,7 @@ class HttpServerSocket : public BufferedSocket { FileReader* index; HttpState InternalState; + std::string ip; HTTPHeaders headers; std::string reqbuffer; @@ -48,7 +49,8 @@ class HttpServerSocket : public BufferedSocket public: - HttpServerSocket(InspIRCd* SI, int newfd, const char* ip, FileReader* ind) : BufferedSocket(SI, newfd, ip), index(ind), postsize(0) + HttpServerSocket(int newfd, const char* IP, FileReader* ind) + : BufferedSocket(newfd), index(ind), ip(IP), postsize(0) { InternalState = HTTP_SERVE_WAIT_REQUEST; } @@ -62,7 +64,7 @@ class HttpServerSocket : public BufferedSocket { } - virtual void OnClose() + virtual void OnError(BufferedSocketError) { } @@ -164,15 +166,15 @@ class HttpServerSocket : public BufferedSocket "Powered by InspIRCd"; SendHeaders(data.length(), response, empty); - this->Write(data); + WriteData(data); } void SendHeaders(unsigned long size, int response, HTTPHeaders &rheaders) { - this->Write(http_version + " "+ConvToStr(response)+" "+Response(response)+"\r\n"); + WriteData(http_version + " "+ConvToStr(response)+" "+Response(response)+"\r\n"); - time_t local = this->ServerInstance->Time(); + time_t local = ServerInstance->Time(); struct tm *timeinfo = gmtime(&local); char *date = asctime(timeinfo); date[strlen(date) - 1] = '\0'; @@ -191,40 +193,32 @@ class HttpServerSocket : public BufferedSocket */ rheaders.SetHeader("Connection", "Close"); - this->Write(rheaders.GetFormattedHeaders()); - this->Write("\r\n"); + WriteData(rheaders.GetFormattedHeaders()); + WriteData("\r\n"); } - virtual bool OnDataReady() + void OnDataReady() { - const char* data = this->Read(); - - /* Check that the data read is a valid pointer and it has some content */ - if (!data || !*data) - return false; - if (InternalState == HTTP_SERVE_RECV_POSTDATA) { - postdata.append(data); + postdata.append(recvq); if (postdata.length() >= postsize) ServeData(); } else { - reqbuffer.append(data); + reqbuffer.append(recvq); if (reqbuffer.length() >= 8192) { ServerInstance->Logs->Log("m_httpd",DEBUG, "m_httpd dropped connection due to an oversized request buffer"); reqbuffer.clear(); - return false; + SetError("Buffer"); } if (InternalState == HTTP_SERVE_WAIT_REQUEST) CheckRequestBuffer(); } - - return true; } void CheckRequestBuffer() @@ -314,18 +308,18 @@ class HttpServerSocket : public BufferedSocket { HTTPHeaders empty; SendHeaders(index->ContentSize(), 200, empty); - this->Write(index->Contents()); + WriteData(index->Contents()); } else { claimed = false; - HTTPRequest httpr(request_type,uri,&headers,this,this->GetIP(),postdata); + HTTPRequest httpr(request_type,uri,&headers,this,ip,postdata); Event acl((char*)&httpr, (Module*)HttpModule, "httpd_acl"); - acl.Send(this->ServerInstance); + acl.Send(ServerInstance); if (!claimed) { Event e((char*)&httpr, (Module*)HttpModule, "httpd_url"); - e.Send(this->ServerInstance); + e.Send(ServerInstance); if (!claimed) { SendHTTPError(404); @@ -337,7 +331,7 @@ class HttpServerSocket : public BufferedSocket void Page(std::stringstream* n, int response, HTTPHeaders *hheaders) { SendHeaders(n->str().length(), response, *hheaders); - this->Write(n->str()); + WriteData(n->str()); } }; @@ -358,7 +352,7 @@ class HttpListener : public ListenSocketBase int port; std::string incomingip; irc::sockets::satoap(&client, incomingip, port); - new HttpServerSocket(ServerInstance, nfd, incomingip.c_str(), index); + new HttpServerSocket(nfd, incomingip.c_str(), index); } }; @@ -426,7 +420,6 @@ class ModuleHttpServer : public Module httpsocks[i]->Close(); delete httpsocks[i]->GetIndex(); } - ServerInstance->BufferedSocketCull(); } virtual Version GetVersion() diff --git a/src/modules/m_spanningtree/addline.cpp b/src/modules/m_spanningtree/addline.cpp index 2f7b5132d..3e6d38070 100644 --- a/src/modules/m_spanningtree/addline.cpp +++ b/src/modules/m_spanningtree/addline.cpp @@ -24,7 +24,7 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 6) { - this->ServerInstance->SNO->WriteToSnoMask('d',"%s sent me a malformed ADDLINE of type %s.",prefix.c_str(),params[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('d',"%s sent me a malformed ADDLINE of type %s.",prefix.c_str(),params[0].c_str()); return true; } @@ -43,7 +43,7 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) if (!xlf) { - this->ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str()); return true; } @@ -54,7 +54,7 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) } catch (ModuleException &e) { - this->ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason()); + ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason()); return true; } xl->SetCreateTime(atoi(params[3].c_str())); @@ -62,12 +62,12 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) { if (xl->duration) { - this->ServerInstance->SNO->WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", + ServerInstance->SNO->WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", params[1].c_str(),ServerInstance->TimeString(xl->expiry).c_str(),params[5].c_str()); } else { - this->ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", + ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", params[1].c_str(),params[5].c_str()); } params[5] = ":" + params[5]; diff --git a/src/modules/m_spanningtree/admin.cpp b/src/modules/m_spanningtree/admin.cpp index 133da928b..e47078c7e 100644 --- a/src/modules/m_spanningtree/admin.cpp +++ b/src/modules/m_spanningtree/admin.cpp @@ -25,30 +25,30 @@ bool TreeSocket::Admin(const std::string &prefix, parameterlist ¶ms) { if (params.size() > 0) { - if (InspIRCd::Match(this->ServerInstance->Config->ServerName, params[0])) + if (InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) { /* It's for our server */ string_list results; - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) { parameterlist par; par.push_back(prefix); par.push_back(""); par[1] = std::string("::")+ServerInstance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+ServerInstance->Config->ServerName; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); par[1] = std::string("::")+ServerInstance->Config->ServerName+" 257 "+source->nick+" :Name - "+ServerInstance->Config->AdminName; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); par[1] = std::string("::")+ServerInstance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+ServerInstance->Config->AdminNick; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); par[1] = std::string("::")+ServerInstance->Config->ServerName+" 258 "+source->nick+" :E-Mail - "+ServerInstance->Config->AdminEmail; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); } } else { /* Pass it on */ - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) Utils->DoOneToOne(prefix, "ADMIN", params, params[0]); } diff --git a/src/modules/m_spanningtree/away.cpp b/src/modules/m_spanningtree/away.cpp index 2aac26bbd..354266554 100644 --- a/src/modules/m_spanningtree/away.cpp +++ b/src/modules/m_spanningtree/away.cpp @@ -20,7 +20,7 @@ bool TreeSocket::Away(const std::string &prefix, parameterlist ¶ms) { - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (!u) return true; if (params.size()) diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp index 66d448e55..7953468e4 100644 --- a/src/modules/m_spanningtree/capab.cpp +++ b/src/modules/m_spanningtree/capab.cpp @@ -23,7 +23,7 @@ std::string TreeSocket::MyModules(int filter) { - std::vector modlist = this->ServerInstance->Modules->GetAllModuleNames(filter); + std::vector modlist = ServerInstance->Modules->GetAllModuleNames(filter); if (filter == VF_COMMON && proto_version != ProtocolVersion) CompatAddModules(modlist); @@ -236,13 +236,13 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } } - if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != this->ServerInstance->Modes->BuildPrefixes()) + if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) reason = "One or more of the prefixes on the remote server are invalid on this server."; - if(this->CapKeys.find("CHANMODES") != this->CapKeys.end() && this->CapKeys.find("CHANMODES")->second != this->ServerInstance->Modes->GiveModeList(MASK_CHANNEL)) + if(this->CapKeys.find("CHANMODES") != this->CapKeys.end() && this->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MASK_CHANNEL)) reason = "One or more of the channel modes on the remote server are invalid on this server."; - if(this->CapKeys.find("USERMODES") != this->CapKeys.end() && this->CapKeys.find("USERMODES")->second != this->ServerInstance->Modes->GiveModeList(MASK_USER)) + if(this->CapKeys.find("USERMODES") != this->CapKeys.end() && this->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MASK_USER)) reason = "One or more of the user modes on the remote server are invalid on this server."; @@ -255,8 +255,8 @@ bool TreeSocket::Capab(const parameterlist ¶ms) if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) { this->SendCapabilities(2); - this->WriteLine(std::string("SERVER ")+this->ServerInstance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 "+ - ServerInstance->Config->GetSID()+" :"+this->ServerInstance->Config->ServerDesc); + this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 "+ + ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } else @@ -265,7 +265,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) if (this->LinkState == CONNECTING) { this->SendCapabilities(2); - this->WriteLine(std::string("SERVER ")+this->ServerInstance->Config->ServerName+" "+OutboundPass+" 0 "+ServerInstance->Config->GetSID()+" :"+this->ServerInstance->Config->ServerDesc); + this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+OutboundPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index 8a6e6855f..71272edec 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -82,7 +82,7 @@ void TreeSocket::WriteLine(std::string line) ServerInstance->Logs->Log("m_spanningtree",DEBUG, "S[%d] O %s", this->GetFd(), line.c_str()); line.append("\r\n"); - this->Write(line); + this->WriteData(line); } diff --git a/src/modules/m_spanningtree/delline.cpp b/src/modules/m_spanningtree/delline.cpp index a1a9089ad..cadcdd14b 100644 --- a/src/modules/m_spanningtree/delline.cpp +++ b/src/modules/m_spanningtree/delline.cpp @@ -42,7 +42,7 @@ bool TreeSocket::DelLine(const std::string &prefix, parameterlist ¶ms) /* NOTE: No check needed on 'user', this function safely handles NULL */ if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user)) { - this->ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(), + ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str()); Utils->DoOneToAllButSender(prefix,"DELLINE", params, prefix); } diff --git a/src/modules/m_spanningtree/encap.cpp b/src/modules/m_spanningtree/encap.cpp index 7b85a49d0..175257b0a 100644 --- a/src/modules/m_spanningtree/encap.cpp +++ b/src/modules/m_spanningtree/encap.cpp @@ -29,7 +29,7 @@ bool TreeSocket::Encap(const std::string &prefix, parameterlist ¶ms) { if (InspIRCd::Match(ServerInstance->Config->GetSID(), params[0])) { - User* who = this->ServerInstance->FindUUID(prefix); + User* who = ServerInstance->FindUUID(prefix); if (!who) who = Utils->ServerUser; diff --git a/src/modules/m_spanningtree/fhost.cpp b/src/modules/m_spanningtree/fhost.cpp index 1595b98aa..d31cffa39 100644 --- a/src/modules/m_spanningtree/fhost.cpp +++ b/src/modules/m_spanningtree/fhost.cpp @@ -25,7 +25,7 @@ bool TreeSocket::ChangeHost(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 1) return true; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { diff --git a/src/modules/m_spanningtree/fident.cpp b/src/modules/m_spanningtree/fident.cpp index 0744d9bf2..8cd3618db 100644 --- a/src/modules/m_spanningtree/fident.cpp +++ b/src/modules/m_spanningtree/fident.cpp @@ -25,7 +25,7 @@ bool TreeSocket::ChangeIdent(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 1) return true; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { u->ChangeIdent(params[0].c_str()); diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index 2c3606db1..7f11f40dd 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -59,7 +59,7 @@ bool TreeSocket::ForceJoin(const std::string &source, parameterlist ¶ms) time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */ irc::tokenstream users((params.size() > 3) ? params[params.size() - 1] : ""); /* users from the user list */ bool apply_other_sides_modes = true; /* True if we are accepting the other side's modes */ - Channel* chan = this->ServerInstance->FindChan(channel); /* The channel we're sending joins to */ + Channel* chan = ServerInstance->FindChan(channel); /* The channel we're sending joins to */ bool created = !chan; /* True if the channel doesnt exist here yet */ std::string item; /* One item in the list of nicks */ @@ -123,7 +123,7 @@ bool TreeSocket::ForceJoin(const std::string &source, parameterlist ¶ms) modelist.push_back(params[idx]); } - this->ServerInstance->SendMode(modelist, Utils->ServerUser); + ServerInstance->SendMode(modelist, Utils->ServerUser); } /* Now, process every 'modes,nick' pair */ @@ -156,7 +156,7 @@ bool TreeSocket::ForceJoin(const std::string &source, parameterlist ¶ms) usr++; /* Check the user actually exists */ - who = this->ServerInstance->FindUUID(usr); + who = ServerInstance->FindUUID(usr); if (who) { /* Check that the user's 'direction' is correct */ @@ -168,7 +168,7 @@ bool TreeSocket::ForceJoin(const std::string &source, parameterlist ¶ms) for (std::string::iterator x = modes.begin(); x != modes.end(); ++x) modestack.Push(*x, who->nick); - Channel::JoinUser(this->ServerInstance, who, channel.c_str(), true, "", route_back_again->bursting, TS); + Channel::JoinUser(ServerInstance, who, channel.c_str(), true, "", route_back_again->bursting, TS); } else { diff --git a/src/modules/m_spanningtree/fmode.cpp b/src/modules/m_spanningtree/fmode.cpp index 3421f8045..3bca098d6 100644 --- a/src/modules/m_spanningtree/fmode.cpp +++ b/src/modules/m_spanningtree/fmode.cpp @@ -34,7 +34,7 @@ bool TreeSocket::ForceMode(const std::string &source, parameterlist ¶ms) std::string sourceserv; /* Are we dealing with an FMODE from a user, or from a server? */ - User* who = this->ServerInstance->FindNick(source); + User* who = ServerInstance->FindNick(source); if (who) { /* FMODE from a user, set sourceserv to the users server name */ @@ -66,7 +66,7 @@ bool TreeSocket::ForceMode(const std::string &source, parameterlist ¶ms) } /* Extract the TS value of the object, either User or Channel */ - User* dst = this->ServerInstance->FindNick(params[0]); + User* dst = ServerInstance->FindNick(params[0]); Channel* chan = NULL; time_t ourTS = 0; @@ -76,7 +76,7 @@ bool TreeSocket::ForceMode(const std::string &source, parameterlist ¶ms) } else { - chan = this->ServerInstance->FindChan(params[0]); + chan = ServerInstance->FindChan(params[0]); if (chan) { ourTS = chan->age; diff --git a/src/modules/m_spanningtree/fname.cpp b/src/modules/m_spanningtree/fname.cpp index a83591a4f..cc7625f12 100644 --- a/src/modules/m_spanningtree/fname.cpp +++ b/src/modules/m_spanningtree/fname.cpp @@ -25,7 +25,7 @@ bool TreeSocket::ChangeName(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 1) return true; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { u->ChangeName(params[0].c_str()); diff --git a/src/modules/m_spanningtree/ftopic.cpp b/src/modules/m_spanningtree/ftopic.cpp index 34e97dd11..5a6656e3e 100644 --- a/src/modules/m_spanningtree/ftopic.cpp +++ b/src/modules/m_spanningtree/ftopic.cpp @@ -27,14 +27,14 @@ bool TreeSocket::ForceTopic(const std::string &source, parameterlist ¶ms) if (params.size() != 4) return true; time_t ts = atoi(params[1].c_str()); - Channel* c = this->ServerInstance->FindChan(params[0]); + Channel* c = ServerInstance->FindChan(params[0]); if (c) { if ((ts >= c->topicset) || (c->topic.empty())) { if (c->topic != params[3]) { - User* user = this->ServerInstance->FindNick(source); + User* user = ServerInstance->FindNick(source); // Update topic only when it differs from current topic c->topic.assign(params[3], 0, ServerInstance->Config->Limits.MaxTopic); if (!user) diff --git a/src/modules/m_spanningtree/handshaketimer.cpp b/src/modules/m_spanningtree/handshaketimer.cpp index 56f34283b..814aa122c 100644 --- a/src/modules/m_spanningtree/handshaketimer.cpp +++ b/src/modules/m_spanningtree/handshaketimer.cpp @@ -37,15 +37,15 @@ HandshakeTimer::~HandshakeTimer() void HandshakeTimer::Tick(time_t TIME) { - if (!sock->GetHook()) + if (!sock->GetIOHook()) { CancelRepeat(); sock->SendCapabilities(1); } - else if (BufferedSocketHSCompleteRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send()) + else if (BufferedSocketHSCompleteRequest(sock, Utils->Creator, sock->GetIOHook()).Send()) { CancelRepeat(); - BufferedSocketAttachCertRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send(); + BufferedSocketAttachCertRequest(sock, Utils->Creator, sock->GetIOHook()).Send(); sock->SendCapabilities(1); } // otherwise, try again later diff --git a/src/modules/m_spanningtree/hmac.cpp b/src/modules/m_spanningtree/hmac.cpp index cc1b33f23..b7cddc47a 100644 --- a/src/modules/m_spanningtree/hmac.cpp +++ b/src/modules/m_spanningtree/hmac.cpp @@ -129,9 +129,9 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) this->auth_challenge = !ourchallenge.empty() && !theirchallenge.empty(); std::string fp; - if (GetHook()) + if (GetIOHook()) { - BufferedSocketCertificateRequest req(this, Utils->Creator, GetHook()); + BufferedSocketCertificateRequest req(this, Utils->Creator, GetIOHook()); req.Send(); if (req.cert) { diff --git a/src/modules/m_spanningtree/kill.cpp b/src/modules/m_spanningtree/kill.cpp index c2026d0bb..e76fc7f3e 100644 --- a/src/modules/m_spanningtree/kill.cpp +++ b/src/modules/m_spanningtree/kill.cpp @@ -28,7 +28,7 @@ bool TreeSocket::RemoteKill(const std::string &prefix, parameterlist ¶ms) if (params.size() != 2) return true; - User* who = this->ServerInstance->FindNick(params[0]); + User* who = ServerInstance->FindNick(params[0]); if (who) { @@ -46,7 +46,7 @@ bool TreeSocket::RemoteKill(const std::string &prefix, parameterlist ¶ms) // this shouldn't ever be null, but it doesn't hurt to check who->Write(":%s KILL %s :%s (%s)", src->GetName().c_str(), who->nick.c_str(), src->GetName().c_str(), reason.c_str()); } - this->ServerInstance->Users->QuitUser(who, reason); + ServerInstance->Users->QuitUser(who, reason); } return true; } diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 1bc3dfe39..230c3109b 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -275,7 +275,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) /* Gave a hook, but it wasnt one we know */ if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end())) return; - TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port, x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, y, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]); + TreeSocket* newsocket = new TreeSocket(Utils, x->IPAddr,x->Port, x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, y, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ @@ -283,8 +283,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) else { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); - if (ServerInstance->SocketCull.find(newsocket) == ServerInstance->SocketCull.end()) - ServerInstance->SocketCull[newsocket] = newsocket; + ServerInstance->GlobalCulls.AddItem(newsocket); Utils->DoFailOver(y); } } diff --git a/src/modules/m_spanningtree/metadata.cpp b/src/modules/m_spanningtree/metadata.cpp index 40a98d93b..135970a4a 100644 --- a/src/modules/m_spanningtree/metadata.cpp +++ b/src/modules/m_spanningtree/metadata.cpp @@ -33,26 +33,26 @@ bool TreeSocket::MetaData(const std::string &prefix, parameterlist ¶ms) { if (params[0] == "*") { - FOREACH_MOD_I(this->ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],params[2])); + FOREACH_MOD_I(ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],params[2])); } else if (*(params[0].c_str()) == '#') { - Channel* c = this->ServerInstance->FindChan(params[0]); + Channel* c = ServerInstance->FindChan(params[0]); if (c) { if (item) item->unserialize(FORMAT_NETWORK, c, params[2]); - FOREACH_MOD_I(this->ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(c,params[1],params[2])); + FOREACH_MOD_I(ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(c,params[1],params[2])); } } else if (*(params[0].c_str()) != '#') { - User* u = this->ServerInstance->FindNick(params[0]); + User* u = ServerInstance->FindNick(params[0]); if (u) { if (item) item->unserialize(FORMAT_NETWORK, u, params[2]); - FOREACH_MOD_I(this->ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],params[2])); + FOREACH_MOD_I(ServerInstance,I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],params[2])); } } } diff --git a/src/modules/m_spanningtree/modules.cpp b/src/modules/m_spanningtree/modules.cpp index 6c9132794..7a20a98ff 100644 --- a/src/modules/m_spanningtree/modules.cpp +++ b/src/modules/m_spanningtree/modules.cpp @@ -26,7 +26,7 @@ bool TreeSocket::Modules(const std::string &prefix, parameterlist ¶ms) if (params.empty()) return true; - if (!InspIRCd::Match(this->ServerInstance->Config->ServerName, params[0])) + if (!InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) { /* Pass it on, not for us */ Utils->DoOneToOne(prefix, "MODULES", params, params[0]); @@ -38,7 +38,7 @@ bool TreeSocket::Modules(const std::string &prefix, parameterlist ¶ms) par.push_back(prefix); par.push_back(""); - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (!source) return true; diff --git a/src/modules/m_spanningtree/motd.cpp b/src/modules/m_spanningtree/motd.cpp index e42c53152..0c775d644 100644 --- a/src/modules/m_spanningtree/motd.cpp +++ b/src/modules/m_spanningtree/motd.cpp @@ -27,11 +27,11 @@ bool TreeSocket::Motd(const std::string &prefix, parameterlist ¶ms) { if (params.size() > 0) { - if (InspIRCd::Match(this->ServerInstance->Config->ServerName, params[0])) + if (InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) { /* It's for our server */ string_list results; - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) { @@ -42,27 +42,27 @@ bool TreeSocket::Motd(const std::string &prefix, parameterlist ¶ms) if (!ServerInstance->Config->MOTD.size()) { par[1] = std::string("::")+ServerInstance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing."; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); return true; } par[1] = std::string("::")+ServerInstance->Config->ServerName+" 375 "+source->nick+" :"+ServerInstance->Config->ServerName+" message of the day"; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); for (unsigned int i = 0; i < ServerInstance->Config->MOTD.size(); i++) { par[1] = std::string("::")+ServerInstance->Config->ServerName+" 372 "+source->nick+" :- "+ServerInstance->Config->MOTD[i]; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); } par[1] = std::string("::")+ServerInstance->Config->ServerName+" 376 "+source->nick+" :End of message of the day."; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); } } else { /* Pass it on */ - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) Utils->DoOneToOne(prefix, "MOTD", params, params[0]); } diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index ada10e6a1..3cfad9b63 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -30,16 +30,16 @@ void TreeSocket::DoBurst(TreeServer* s) { std::string name = s->GetName(); - std::string burst = ":" + this->ServerInstance->Config->GetSID() + " BURST " +ConvToStr(ServerInstance->Time()); - std::string endburst = ":" + this->ServerInstance->Config->GetSID() + " ENDBURST"; - this->ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s%s).", + std::string burst = ":" + ServerInstance->Config->GetSID() + " BURST " +ConvToStr(ServerInstance->Time()); + std::string endburst = ":" + ServerInstance->Config->GetSID() + " ENDBURST"; + ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s%s).", name.c_str(), this->auth_fingerprint ? "SSL Fingerprint and " : "", this->auth_challenge ? "challenge-response" : "plaintext password"); this->CleanNegotiationInfo(); this->WriteLine(burst); /* send our version string */ - this->WriteLine(std::string(":")+this->ServerInstance->Config->GetSID()+" VERSION :"+this->ServerInstance->GetVersionString()); + this->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" VERSION :"+ServerInstance->GetVersionString()); /* Send server tree */ this->SendServers(Utils->TreeRoot,s,1); /* Send users and their oper status */ @@ -47,9 +47,9 @@ void TreeSocket::DoBurst(TreeServer* s) /* Send everything else (channel modes, xlines etc) */ this->SendChannelModes(s); this->SendXLines(s); - FOREACH_MOD_I(this->ServerInstance,I_OnSyncNetwork,OnSyncNetwork(Utils->Creator,(void*)this)); + FOREACH_MOD_I(ServerInstance,I_OnSyncNetwork,OnSyncNetwork(Utils->Creator,(void*)this)); this->WriteLine(endburst); - this->ServerInstance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2."); + ServerInstance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2."); } /** Recursively send the server tree with distances as hops. @@ -91,7 +91,7 @@ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) size_t curlen, headlen; curlen = headlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu +%s :", - this->ServerInstance->Config->GetSID().c_str(), c->name.c_str(), (unsigned long)c->age, c->ChanModes(true)); + ServerInstance->Config->GetSID().c_str(), c->name.c_str(), (unsigned long)c->age, c->ChanModes(true)); int numusers = 0; char* ptr = list + curlen; bool looped_once = false; @@ -103,7 +103,7 @@ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { size_t ptrlen = 0; - std::string modestr = this->ServerInstance->Modes->ModeString(i->first, c, false); + std::string modestr = ServerInstance->Modes->ModeString(i->first, c, false); if ((curlen + modestr.length() + i->first->uuid.length() + 4) > 480) { @@ -150,7 +150,7 @@ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) if ((params.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350)) { /* Wrap at MAXMODES */ - buffer.append(":").append(this->ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); + buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); modes.clear(); params.clear(); linesize = 1; @@ -159,7 +159,7 @@ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) /* Only send these if there are any */ if (!modes.empty()) - buffer.append(":").append(this->ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); + buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); this->WriteLine(buffer); } @@ -168,7 +168,7 @@ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) void TreeSocket::SendXLines(TreeServer* Current) { char data[MAXBUF]; - std::string n = this->ServerInstance->Config->GetSID(); + std::string n = ServerInstance->Config->GetSID(); const char* sn = n.c_str(); std::vector types = ServerInstance->XLines->GetAllTypes(); @@ -209,9 +209,9 @@ void TreeSocket::SendChannelModes(TreeServer* Current) { char data[MAXBUF]; std::deque list; - std::string n = this->ServerInstance->Config->GetSID(); + std::string n = ServerInstance->Config->GetSID(); const char* sn = n.c_str(); - for (chan_hash::iterator c = this->ServerInstance->chanlist->begin(); c != this->ServerInstance->chanlist->end(); c++) + for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++) { SendFJoins(Current, c->second); if (!c->second->topic.empty()) @@ -230,7 +230,7 @@ void TreeSocket::SendChannelModes(TreeServer* Current) Utils->Creator->ProtoSendMetaData(this, c->second, i->first, value); } - FOREACH_MOD_I(this->ServerInstance,I_OnSyncChannel,OnSyncChannel(c->second,Utils->Creator,this)); + FOREACH_MOD_I(ServerInstance,I_OnSyncChannel,OnSyncChannel(c->second,Utils->Creator,this)); } } @@ -239,7 +239,7 @@ void TreeSocket::SendUsers(TreeServer* Current) { char data[MAXBUF]; std::string dataline; - for (user_hash::iterator u = this->ServerInstance->Users->clientlist->begin(); u != this->ServerInstance->Users->clientlist->end(); u++) + for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { @@ -281,7 +281,7 @@ void TreeSocket::SendUsers(TreeServer* Current) Utils->Creator->ProtoSendMetaData(this, u->second, i->first, value); } - FOREACH_MOD_I(this->ServerInstance,I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this)); + FOREACH_MOD_I(ServerInstance,I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this)); } } } diff --git a/src/modules/m_spanningtree/nickcollide.cpp b/src/modules/m_spanningtree/nickcollide.cpp index a723c114f..4481ba35e 100644 --- a/src/modules/m_spanningtree/nickcollide.cpp +++ b/src/modules/m_spanningtree/nickcollide.cpp @@ -114,7 +114,7 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei } if (bChangeRemote) { - User *remote = this->ServerInstance->FindUUID(remoteuid); + User *remote = ServerInstance->FindUUID(remoteuid); /* * remote side needs to change. If this happens, we will modify * the UID or halt the propagation of the nick change command, diff --git a/src/modules/m_spanningtree/operquit.cpp b/src/modules/m_spanningtree/operquit.cpp index 5cdee3bc6..9128baa0f 100644 --- a/src/modules/m_spanningtree/operquit.cpp +++ b/src/modules/m_spanningtree/operquit.cpp @@ -26,7 +26,7 @@ bool TreeSocket::OperQuit(const std::string &prefix, parameterlist ¶ms) if (params.size() < 1) return true; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { diff --git a/src/modules/m_spanningtree/opertype.cpp b/src/modules/m_spanningtree/opertype.cpp index c1105aa71..a1ad88007 100644 --- a/src/modules/m_spanningtree/opertype.cpp +++ b/src/modules/m_spanningtree/opertype.cpp @@ -29,11 +29,11 @@ bool TreeSocket::OperType(const std::string &prefix, parameterlist ¶ms) if (params.size() != 1) return true; std::string opertype = params[0]; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { if (!IS_OPER(u)) - this->ServerInstance->Users->all_opers.push_back(u); + ServerInstance->Users->all_opers.push_back(u); u->modes[UM_OPERATOR] = 1; u->oper.assign(opertype, 0, 512); Utils->DoOneToAllButSender(u->uuid, "OPERTYPE", params, u->server); @@ -49,7 +49,7 @@ bool TreeSocket::OperType(const std::string &prefix, parameterlist ¶ms) */ if ( remoteserver->bursting || - this->ServerInstance->SilentULine(this->ServerInstance->FindServerNamePtr(u->server)) + ServerInstance->SilentULine(ServerInstance->FindServerNamePtr(u->server)) ) { dosend = false; @@ -57,7 +57,7 @@ bool TreeSocket::OperType(const std::string &prefix, parameterlist ¶ms) } if (dosend) - this->ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick.c_str(),u->ident.c_str(), u->host.c_str(), irc::Spacify(opertype.c_str())); + ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick.c_str(),u->ident.c_str(), u->host.c_str(), irc::Spacify(opertype.c_str())); } return true; } diff --git a/src/modules/m_spanningtree/override_stats.cpp b/src/modules/m_spanningtree/override_stats.cpp index 9986763d9..5d0239f84 100644 --- a/src/modules/m_spanningtree/override_stats.cpp +++ b/src/modules/m_spanningtree/override_stats.cpp @@ -78,8 +78,8 @@ ModResult ModuleSpanningTree::OnStats(char statschar, User* user, string_list &r ip = "*"; std::string transport("plaintext"); - if (Utils->Bindings[i]->GetIOHook()) - transport = BufferedSocketNameRequest(this, Utils->Bindings[i]->GetIOHook()).Send(); + if (Utils->Bindings[i]->Hook) + transport = BufferedSocketNameRequest(this, Utils->Bindings[i]->Hook).Send(); results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->GetPort())+ " (server, " + transport + ")"); diff --git a/src/modules/m_spanningtree/ping.cpp b/src/modules/m_spanningtree/ping.cpp index 1318b60a0..c3467c984 100644 --- a/src/modules/m_spanningtree/ping.cpp +++ b/src/modules/m_spanningtree/ping.cpp @@ -31,13 +31,13 @@ bool TreeSocket::LocalPing(const std::string &prefix, parameterlist ¶ms) if (params.size() == 1) { std::string stufftobounce = params[0]; - this->WriteLine(std::string(":")+this->ServerInstance->Config->GetSID()+" PONG "+stufftobounce); + this->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" PONG "+stufftobounce); return true; } else { std::string forwardto = params[1]; - if (forwardto == this->ServerInstance->Config->ServerName || forwardto == this->ServerInstance->Config->GetSID()) + if (forwardto == ServerInstance->Config->ServerName || forwardto == ServerInstance->Config->GetSID()) { // this is a ping for us, send back PONG to the requesting server params[1] = params[0]; diff --git a/src/modules/m_spanningtree/pong.cpp b/src/modules/m_spanningtree/pong.cpp index b551ef6d2..274641897 100644 --- a/src/modules/m_spanningtree/pong.cpp +++ b/src/modules/m_spanningtree/pong.cpp @@ -52,7 +52,7 @@ bool TreeSocket::LocalPong(const std::string &prefix, parameterlist ¶ms) * dump the PONG reply back to their fd. If its a server, do nowt. * Services might want to send these s->s, but we dont need to yet. */ - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str()); diff --git a/src/modules/m_spanningtree/push.cpp b/src/modules/m_spanningtree/push.cpp index 88c6b55bd..778c2291c 100644 --- a/src/modules/m_spanningtree/push.cpp +++ b/src/modules/m_spanningtree/push.cpp @@ -28,7 +28,7 @@ bool TreeSocket::Push(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 2) return true; - User* u = this->ServerInstance->FindNick(params[0]); + User* u = ServerInstance->FindNick(params[0]); if (!u) return true; if (IS_LOCAL(u)) diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp index 73e67c4f7..c7c49b348 100644 --- a/src/modules/m_spanningtree/resolvers.cpp +++ b/src/modules/m_spanningtree/resolvers.cpp @@ -49,7 +49,7 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in if ((!MyLink.Hook.empty()) && (Utils->hooks.find(MyLink.Hook.c_str()) == Utils->hooks.end())) return; - TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(), + TreeSocket* newsocket = new TreeSocket(this->Utils, result,MyLink.Port,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(), MyLink.Bind, myautoconnect, MyLink.Hook.empty() ? NULL : Utils->hooks[MyLink.Hook.c_str()]); if (newsocket->GetFd() > -1) { @@ -59,8 +59,7 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in { /* Something barfed, show the opers */ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno)); - if (ServerInstance->SocketCull.find(newsocket) == ServerInstance->SocketCull.end()) - ServerInstance->SocketCull[newsocket] = newsocket; + ServerInstance->GlobalCulls.AddItem(newsocket); Utils->DoFailOver(myautoconnect); } } diff --git a/src/modules/m_spanningtree/save.cpp b/src/modules/m_spanningtree/save.cpp index 9969fdca7..cfa8dc794 100644 --- a/src/modules/m_spanningtree/save.cpp +++ b/src/modules/m_spanningtree/save.cpp @@ -32,7 +32,7 @@ bool TreeSocket::ForceNick(const std::string &prefix, parameterlist ¶ms) if (params.size() < 2) return true; - User* u = this->ServerInstance->FindNick(params[0]); + User* u = ServerInstance->FindNick(params[0]); time_t ts = atol(params[1].c_str()); if (u && u->age == ts) @@ -41,7 +41,7 @@ bool TreeSocket::ForceNick(const std::string &prefix, parameterlist ¶ms) if (!u->ForceNickChange(u->uuid.c_str())) { - this->ServerInstance->Users->QuitUser(u, "Nickname collision"); + ServerInstance->Users->QuitUser(u, "Nickname collision"); } } diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp index c275f3490..025675642 100644 --- a/src/modules/m_spanningtree/server.cpp +++ b/src/modules/m_spanningtree/server.cpp @@ -49,7 +49,7 @@ bool TreeSocket::RemoteServer(const std::string &prefix, parameterlist ¶ms) this->SendError("Protocol error - Introduced remote server from unknown server "+ParentOfThis->GetName()); return false; } - if (!this->ServerInstance->IsSID(sid)) + if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return false; @@ -58,26 +58,26 @@ bool TreeSocket::RemoteServer(const std::string &prefix, parameterlist ¶ms) if (CheckDupe) { this->SendError("Server "+servername+" already exists!"); - this->ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName()); + ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName()); return false; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { this->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with so they do not conflict."); - this->ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); + ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); return false; } Link* lnk = Utils->FindLink(servername); - TreeServer *Node = new TreeServer(this->Utils, this->ServerInstance, servername, description, sid, ParentOfThis,NULL, lnk ? lnk->Hidden : false); + TreeServer *Node = new TreeServer(this->Utils, ServerInstance, servername, description, sid, ParentOfThis,NULL, lnk ? lnk->Hidden : false); ParentOfThis->AddChild(Node); params[4] = ":" + params[4]; Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix); - this->ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); + ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); return true; } @@ -110,11 +110,11 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) if (hops) { this->SendError("Server too far away for authentication"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); return false; } - if (!this->ServerInstance->IsSID(sid)) + if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return false; @@ -127,7 +127,7 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) if (!ComparePass(*x, password)) { - this->ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); continue; } @@ -135,14 +135,14 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) if (CheckDupe) { this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); return false; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { this->SendError("Server ID "+sid+" already exists on the network! You may want to specify the server ID for the server manually with so they do not conflict."); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server \2"+assign(servername)+"\2 being introduced denied, server ID already exists on the network. Closing link."); + ServerInstance->SNO->WriteToSnoMask('l',"Server \2"+assign(servername)+"\2 being introduced denied, server ID already exists on the network. Closing link."); return false; } @@ -158,7 +158,7 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) Utils->timeoutlist.erase(this); - TreeServer *Node = new TreeServer(this->Utils, this->ServerInstance, sname, description, sid, Utils->TreeRoot, this, x->Hidden); + TreeServer *Node = new TreeServer(this->Utils, ServerInstance, sname, description, sid, Utils->TreeRoot, this, x->Hidden); Utils->TreeRoot->AddChild(Node); params[4] = ":" + params[4]; @@ -173,7 +173,7 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) } this->SendError("Invalid credentials (check the other server's linking snomask for more information)"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return false; } @@ -205,11 +205,11 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) if (hops) { this->SendError("Server too far away for authentication"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); return false; } - if (!this->ServerInstance->IsSID(sid)) + if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return false; @@ -222,7 +222,7 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) if (!ComparePass(*x, password)) { - this->ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); continue; } @@ -231,7 +231,7 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) if (CheckDupe) { this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); return false; } @@ -242,30 +242,30 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) if (CheckDupe) { this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with so they do not conflict."); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ "' already exists on server "+CheckDupe->GetName()); return false; } - this->ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "" : this->GetIP())+"] ("+description+")"); - if (this->Hook) + ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "" : this->IP)+"] ("+description+")"); + if (this->GetIOHook()) { - std::string name = BufferedSocketNameRequest((Module*)Utils->Creator, this->Hook).Send(); - this->ServerInstance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "" : this->GetIP())+"] using transport \2"+name+"\2"); + std::string name = BufferedSocketNameRequest(Utils->Creator, this->GetIOHook()).Send(); + ServerInstance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "" : this->IP)+"] using transport \2"+name+"\2"); } // this is good. Send our details: Our server name and description and hopcount of 0, // along with the sendpass from this block. this->SendCapabilities(2); - this->WriteLine(std::string("SERVER ")+this->ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+this->ServerInstance->Config->ServerDesc); + this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); // move to the next state, we are now waiting for THEM. this->LinkState = WAIT_AUTH_2; return true; } this->SendError("Invalid credentials"); - this->ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return false; } diff --git a/src/modules/m_spanningtree/stats.cpp b/src/modules/m_spanningtree/stats.cpp index d67c5a3af..71f12d50b 100644 --- a/src/modules/m_spanningtree/stats.cpp +++ b/src/modules/m_spanningtree/stats.cpp @@ -32,11 +32,11 @@ bool TreeSocket::Stats(const std::string &prefix, parameterlist ¶ms) */ if (params.size() > 1) { - if (InspIRCd::Match(this->ServerInstance->Config->ServerName, params[1])) + if (InspIRCd::Match(ServerInstance->Config->ServerName, params[1])) { /* It's for our server */ string_list results; - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) { parameterlist par; @@ -46,14 +46,14 @@ bool TreeSocket::Stats(const std::string &prefix, parameterlist ¶ms) for (size_t i = 0; i < results.size(); i++) { par[1] = "::" + results[i]; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(), "PUSH",par, source->server); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH",par, source->server); } } } else { /* Pass it on */ - User* source = this->ServerInstance->FindNick(prefix); + User* source = ServerInstance->FindNick(prefix); if (source) Utils->DoOneToOne(source->uuid, "STATS", params, params[1]); } diff --git a/src/modules/m_spanningtree/svsjoin.cpp b/src/modules/m_spanningtree/svsjoin.cpp index b6246e2f4..1664190f8 100644 --- a/src/modules/m_spanningtree/svsjoin.cpp +++ b/src/modules/m_spanningtree/svsjoin.cpp @@ -29,13 +29,13 @@ bool TreeSocket::ServiceJoin(const std::string &prefix, parameterlist ¶ms) if (params.size() < 2) return true; - User* u = this->ServerInstance->FindNick(params[0]); + User* u = ServerInstance->FindNick(params[0]); if (u) { /* only join if it's local, otherwise just pass it on! */ if (IS_LOCAL(u)) - Channel::JoinUser(this->ServerInstance, u, params[1].c_str(), false, "", false, ServerInstance->Time()); + Channel::JoinUser(ServerInstance, u, params[1].c_str(), false, "", false, ServerInstance->Time()); Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix); } return true; diff --git a/src/modules/m_spanningtree/svsnick.cpp b/src/modules/m_spanningtree/svsnick.cpp index 3af6961d0..7a723a36d 100644 --- a/src/modules/m_spanningtree/svsnick.cpp +++ b/src/modules/m_spanningtree/svsnick.cpp @@ -32,7 +32,7 @@ bool TreeSocket::SVSNick(const std::string &prefix, parameterlist ¶ms) if (params.size() < 3) return true; - User* u = this->ServerInstance->FindNick(params[0]); + User* u = ServerInstance->FindNick(params[0]); if (u) { @@ -48,7 +48,7 @@ bool TreeSocket::SVSNick(const std::string &prefix, parameterlist ¶ms) /* buh. UID them */ if (!u->ForceNickChange(u->uuid.c_str())) { - this->ServerInstance->Users->QuitUser(u, "Nickname collision"); + ServerInstance->Users->QuitUser(u, "Nickname collision"); return true; } } diff --git a/src/modules/m_spanningtree/svspart.cpp b/src/modules/m_spanningtree/svspart.cpp index 83e329b4e..1e26c90d9 100644 --- a/src/modules/m_spanningtree/svspart.cpp +++ b/src/modules/m_spanningtree/svspart.cpp @@ -34,8 +34,8 @@ bool TreeSocket::ServicePart(const std::string &prefix, parameterlist ¶ms) if (params.size() == 3) reason = params[2]; - User* u = this->ServerInstance->FindNick(params[0]); - Channel* c = this->ServerInstance->FindChan(params[1]); + User* u = ServerInstance->FindNick(params[0]); + Channel* c = ServerInstance->FindChan(params[1]); if (u) { diff --git a/src/modules/m_spanningtree/time.cpp b/src/modules/m_spanningtree/time.cpp index 82a7fe62e..6fdcf8b53 100644 --- a/src/modules/m_spanningtree/time.cpp +++ b/src/modules/m_spanningtree/time.cpp @@ -31,20 +31,20 @@ bool TreeSocket::Time(const std::string &prefix, parameterlist ¶ms) if (params.size() == 2) { // someone querying our time? - if (this->ServerInstance->Config->ServerName == params[0] || this->ServerInstance->Config->GetSID() == params[0]) + if (ServerInstance->Config->ServerName == params[0] || ServerInstance->Config->GetSID() == params[0]) { - User* u = this->ServerInstance->FindNick(params[1]); + User* u = ServerInstance->FindNick(params[1]); if (u) { params.push_back(ConvToStr(ServerInstance->Time())); params[0] = prefix; - Utils->DoOneToOne(this->ServerInstance->Config->GetSID(),"TIME",params,params[0]); + Utils->DoOneToOne(ServerInstance->Config->GetSID(),"TIME",params,params[0]); } } else { // not us, pass it on - User* u = this->ServerInstance->FindNick(params[1]); + User* u = ServerInstance->FindNick(params[1]); if (u) Utils->DoOneToOne(prefix,"TIME",params,params[0]); } @@ -52,7 +52,7 @@ bool TreeSocket::Time(const std::string &prefix, parameterlist ¶ms) else if (params.size() == 3) { // a response to a previous TIME - User* u = this->ServerInstance->FindNick(params[1]); + User* u = ServerInstance->FindNick(params[1]); if ((u) && (IS_LOCAL(u))) { std::string sourceserv = Utils->FindServer(prefix)->GetName(); diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index a26e89f85..3c9484981 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -71,7 +71,6 @@ class TreeSocket : public BufferedSocket { SpanningTreeUtilities* Utils; /* Utility class */ std::string myhost; /* Canonical hostname */ - std::string in_buffer; /* Input buffer */ ServerState LinkState; /* Link state */ std::string InboundServerName; /* Server name sent to us by other side */ std::string InboundDescription; /* Server description (GECOS) sent to us by the other side */ @@ -80,10 +79,10 @@ class TreeSocket : public BufferedSocket int num_lost_servers; /* Servers lost in split */ time_t NextPing; /* Time when we are due to ping this server */ bool LastPingWasGood; /* Responded to last ping we sent? */ + std::string IP; std::string ModuleList; /* Required module list of other server from CAPAB */ std::string OptModuleList; /* Optional module list of other server from CAPAB */ std::map CapKeys; /* CAPAB keys from other server */ - Module* Hook; /* I/O hooking module that we're attached to for this socket */ std::string ourchallenge; /* Challenge sent for challenge/response */ std::string theirchallenge; /* Challenge recv for challenge/response */ std::string OutboundPass; /* Outbound password */ @@ -101,13 +100,13 @@ class TreeSocket : public BufferedSocket * most of the action, and append a few of our own values * to it. */ - TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Autoconnect* myac, Module* HookMod = NULL); + TreeSocket(SpanningTreeUtilities* Util, std::string host, int port, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Autoconnect* myac, Module* HookMod = NULL); /** When a listening socket gives us a new file descriptor, * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ - TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Autoconnect* myac, Module* HookMod = NULL); + TreeSocket(SpanningTreeUtilities* Util, int newfd, char* ip, Autoconnect* myac, Module* HookMod = NULL); /** Get link state */ @@ -137,10 +136,6 @@ class TreeSocket : public BufferedSocket */ void CleanNegotiationInfo(); - /** Return the module which we are hooking to for I/O encapsulation - */ - Module* GetHook(); - /** Destructor */ ~TreeSocket(); @@ -160,7 +155,7 @@ class TreeSocket : public BufferedSocket * to server docs on the inspircd.org site, the other side * will then send back its own server string. */ - virtual bool OnConnected(); + virtual void OnConnected(); /** Handle socket error event */ @@ -171,10 +166,6 @@ class TreeSocket : public BufferedSocket */ void SendError(const std::string &errormessage); - /** Handle socket disconnect event - */ - virtual int OnDisconnect(); - /** Recursively send the server tree with distances as hops. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. @@ -258,14 +249,9 @@ class TreeSocket : public BufferedSocket void DoBurst(TreeServer* s); /** This function is called when we receive data from a remote - * server. We buffer the data in a std::string (it doesnt stay - * there for long), reading using BufferedSocket::Read() which can - * read up to 16 kilobytes in one operation. - * - * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES - * THE SOCKET OBJECT FOR US. + * server. */ - virtual bool OnDataReady(); + void OnDataReady(); /** Send one or more complete lines down the socket */ @@ -404,10 +390,9 @@ class TreeSocket : public BufferedSocket /** Handle socket timeout from connect() */ virtual void OnTimeout(); - - /** Handle socket close event + /** Handle server quit on close */ - virtual void OnClose(); + virtual void Close(); }; /* Used to validate the value lengths of multiple parameters for a command */ diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index d59364751..55fbc2c91 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -34,17 +34,18 @@ * most of the action, and append a few of our own values * to it. */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string shost, int iport, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Autoconnect* myac, Module* HookMod) - : BufferedSocket(SI, shost, iport, maxtime, bindto), Utils(Util), Hook(HookMod), myautoconnect(myac) +TreeSocket::TreeSocket(SpanningTreeUtilities* Util, std::string shost, int iport, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Autoconnect* myac, Module* HookMod) + : Utils(Util), IP(shost), myautoconnect(myac) { - age = SI->Time(); + age = ServerInstance->Time(); myhost = ServerName; capab_phase = 0; proto_version = 0; LinkState = CONNECTING; + DoConnect(shost, iport, maxtime, bindto); Utils->timeoutlist[this] = std::pair(ServerName, maxtime); - if (Hook) - BufferedSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); + if (HookMod) + BufferedSocketHookRequest(this, Utils->Creator, HookMod).Send(); hstimer = NULL; } @@ -52,18 +53,18 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string sh * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Autoconnect* myac, Module* HookMod) - : BufferedSocket(SI, newfd, ip), Utils(Util), Hook(HookMod), myautoconnect(myac) +TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, char* ip, Autoconnect* myac, Module* HookMod) + : BufferedSocket(newfd), Utils(Util), IP(ip), myautoconnect(myac) { - age = SI->Time(); + age = ServerInstance->Time(); LinkState = WAIT_AUTH_1; capab_phase = 0; proto_version = 0; /* If we have a transport module hooked to the parent, hook the same module to this * socket, and set a timer waiting for handshake before we send CAPAB etc. */ - if (Hook) - BufferedSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); + if (HookMod) + BufferedSocketHookRequest(this, Utils->Creator, HookMod).Send(); hstimer = new HandshakeTimer(ServerInstance, this, &(Utils->LinkBlocks[0]), this->Utils, 1); ServerInstance->Timers->AddTimer(hstimer); @@ -77,11 +78,6 @@ ServerState TreeSocket::GetLinkState() return this->LinkState; } -Module* TreeSocket::GetHook() -{ - return this->Hook; -} - void TreeSocket::CleanNegotiationInfo() { ModuleList.clear(); @@ -94,8 +90,8 @@ void TreeSocket::CleanNegotiationInfo() TreeSocket::~TreeSocket() { - if (Hook) - BufferedSocketUnhookRequest(this, (Module*)Utils->Creator, Hook).Send(); + if (GetIOHook()) + BufferedSocketUnhookRequest(this, Utils->Creator, GetIOHook()).Send(); if (hstimer) ServerInstance->Timers->DelTimer(hstimer); Utils->timeoutlist.erase(this); @@ -107,7 +103,7 @@ TreeSocket::~TreeSocket() * to server docs on the inspircd.org site, the other side * will then send back its own server string. */ -bool TreeSocket::OnConnected() +void TreeSocket::OnConnected() { if (this->LinkState == CONNECTING) { @@ -116,25 +112,17 @@ bool TreeSocket::OnConnected() { if (x->Name == this->myhost) { - ServerInstance->SNO->WriteToSnoMask('l', "Connection to \2%s\2[%s] started.", myhost.c_str(), (x->HiddenFromStats ? "" : this->GetIP().c_str())); - if (Hook) - { - BufferedSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); - ServerInstance->SNO->WriteToSnoMask('l', "Connection to \2%s\2[%s] using transport \2%s\2", myhost.c_str(), (x->HiddenFromStats ? "" : this->GetIP().c_str()), - x->Hook.c_str()); - } + ServerInstance->SNO->WriteToSnoMask('l', "Connection to \2%s\2[%s] started.", myhost.c_str(), (x->HiddenFromStats ? "" : this->IP.c_str())); this->OutboundPass = x->SendPass; - - /* found who we're supposed to be connecting to, send the neccessary gubbins. */ - if (this->GetHook()) + if (GetIOHook()) { + ServerInstance->SNO->WriteToSnoMask('l', "Connection to \2%s\2[%s] using transport \2%s\2", myhost.c_str(), (x->HiddenFromStats ? "" : this->IP.c_str()), x->Hook.c_str()); hstimer = new HandshakeTimer(ServerInstance, this, &(*x), this->Utils, 1); ServerInstance->Timers->AddTimer(hstimer); } else this->SendCapabilities(1); - - return true; + return; } } } @@ -144,7 +132,6 @@ bool TreeSocket::OnConnected() * and rather harmless. */ ServerInstance->SNO->WriteToSnoMask('l', "Connection to \2%s\2 lost link tag(!)", myhost.c_str()); - return true; } void TreeSocket::OnError(BufferedSocketError e) @@ -174,21 +161,11 @@ void TreeSocket::OnError(BufferedSocketError e) } } -int TreeSocket::OnDisconnect() -{ - /* For the same reason as above, we don't - * handle OnDisconnect() - */ - return true; -} - void TreeSocket::SendError(const std::string &errormessage) { /* Display the error locally as well as sending it remotely */ - ServerInstance->SNO->WriteToSnoMask('l', "Sent \2ERROR\2 to %s: %s", (this->InboundServerName.empty() ? this->GetIP().c_str() : this->InboundServerName.c_str()), errormessage.c_str()); - this->WriteLine("ERROR :"+errormessage); - /* One last attempt to make sure the error reaches its target */ - this->FlushWriteBuffer(); + ServerInstance->SNO->WriteToSnoMask('l', "Sent \2ERROR\2 to %s: %s", (this->InboundServerName.empty() ? this->IP.c_str() : this->InboundServerName.c_str()), errormessage.c_str()); + WriteLine("ERROR :"+errormessage); } /** This function forces this server to quit, removing this server @@ -232,12 +209,12 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) Utils->DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName()); if (Current->GetParent() == Utils->TreeRoot) { - this->ServerInstance->SNO->WriteToSnoMask('l', "Server \002"+Current->GetName()+"\002 split: "+reason); + ServerInstance->SNO->WriteToSnoMask('l', "Server \002"+Current->GetName()+"\002 split: "+reason); LocalSquit = true; } else { - this->ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason); + ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason); } num_lost_servers = 0; num_lost_users = 0; @@ -247,56 +224,41 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) Current->GetParent()->DelChild(Current); delete Current; if (LocalSquit) - this->ServerInstance->SNO->WriteToSnoMask('l', "Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); + ServerInstance->SNO->WriteToSnoMask('l', "Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); else - this->ServerInstance->SNO->WriteToSnoMask('L', "Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); + ServerInstance->SNO->WriteToSnoMask('L', "Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); } else ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Squit from unknown server"); } /** This function is called when we receive data from a remote - * server. We buffer the data in a std::string (it doesnt stay - * there for long), reading using BufferedSocket::Read() which can - * read up to 16 kilobytes in one operation. - * - * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES - * THE SOCKET OBJECT FOR US. + * server. */ -bool TreeSocket::OnDataReady() +void TreeSocket::OnDataReady() { - const char* data = this->Read(); - /* Check that the data read is a valid pointer and it has some content */ - if (data && *data) + Utils->Creator->loopCall = true; + /* While there is at least one new line in the buffer, + * do something useful (we hope!) with it. + */ + while (recvq.find("\n") != std::string::npos) { - this->in_buffer.append(data); - Utils->Creator->loopCall = true; - /* While there is at least one new line in the buffer, - * do something useful (we hope!) with it. + std::string ret = recvq.substr(0,recvq.find("\n")-1); + recvq = recvq.substr(recvq.find("\n")+1,recvq.length()-recvq.find("\n")); + /* Use rfind here not find, as theres more + * chance of the \r being near the end of the + * string, not the start. */ - while (in_buffer.find("\n") != std::string::npos) + if (ret.find("\r") != std::string::npos) + ret = recvq.substr(0,recvq.find("\r")-1); + /* Process this one, abort if it + * didnt return true. + */ + if (!this->ProcessLine(ret)) { - std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1); - in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n")); - /* Use rfind here not find, as theres more - * chance of the \r being near the end of the - * string, not the start. - */ - if (ret.find("\r") != std::string::npos) - ret = in_buffer.substr(0,in_buffer.find("\r")-1); - /* Process this one, abort if it - * didnt return true. - */ - if (!this->ProcessLine(ret)) - { - return false; - } + SetError("ProcessLine returned false"); + break; } - Utils->Creator->loopCall = false; - return true; } - /* EAGAIN returns an empty but non-NULL string, so this - * evaluates to TRUE for EAGAIN but to FALSE for EOF. - */ - return (data && !*data); + Utils->Creator->loopCall = false; } diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index 793802781..cf537f05b 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -32,7 +32,7 @@ bool TreeSocket::Error(parameterlist ¶ms) { if (params.size() < 1) return false; - this->ServerInstance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str()); /* we will return false to cause the socket to close. */ return false; } @@ -126,9 +126,7 @@ bool TreeSocket::ProcessLine(std::string &line) } else { - // XXX ...wtf. - irc::string error = "Invalid command in negotiation phase: " + command; - this->SendError(assign(error)); + this->SendError(std::string("Invalid command in negotiation phase: ") + command.c_str()); return false; } break; @@ -171,7 +169,7 @@ bool TreeSocket::ProcessLine(std::string &line) Link* lnk = Utils->FindLink(InboundServerName); - Node = new TreeServer(this->Utils, this->ServerInstance, InboundServerName, InboundDescription, InboundSID, Utils->TreeRoot, this, lnk ? lnk->Hidden : false); + Node = new TreeServer(this->Utils, ServerInstance, InboundServerName, InboundDescription, InboundSID, Utils->TreeRoot, this, lnk ? lnk->Hidden : false); Utils->TreeRoot->AddChild(Node); parameterlist sparams; @@ -242,7 +240,7 @@ bool TreeSocket::ProcessLine(std::string &line) */ std::string direction = prefix; - User *t = this->ServerInstance->FindUUID(prefix); + User *t = ServerInstance->FindUUID(prefix); if (t) { /* Find UID */ @@ -316,7 +314,7 @@ bool TreeSocket::ProcessLine(std::string &line) } else if ((command == "NOTICE" || command == "PRIVMSG") && (Utils->IsServer(prefix))) { - return this->ServerMessage(assign(command), prefix, params, sourceserv); + return ServerMessage(assign(command), prefix, params, sourceserv); } else if (command == "STATS") { @@ -487,7 +485,7 @@ bool TreeSocket::ProcessLine(std::string &line) // Set prefix server as bursting if (!ServerSource) { - this->ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got BURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); + ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got BURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); return false; } @@ -498,7 +496,7 @@ bool TreeSocket::ProcessLine(std::string &line) { if (!ServerSource) { - this->ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got ENDBURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); + ServerInstance->SNO->WriteToSnoMask('l', "WTF: Got ENDBURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str())); return false; } @@ -515,7 +513,7 @@ bool TreeSocket::ProcessLine(std::string &line) * Not a special s2s command. Emulate the user doing it. * This saves us having a huge ugly command parser again. */ - User* who = this->ServerInstance->FindUUID(prefix); + User* who = ServerInstance->FindUUID(prefix); if (ServerSource) { @@ -546,7 +544,7 @@ bool TreeSocket::ProcessLine(std::string &line) * On nick messages, check that the nick doesnt already exist here. * If it does, perform collision logic. */ - User* x = this->ServerInstance->FindNickOnly(params[0]); + User* x = ServerInstance->FindNickOnly(params[0]); if ((x) && (x != who)) { int collideret = 0; @@ -564,7 +562,7 @@ bool TreeSocket::ProcessLine(std::string &line) } } - switch (this->ServerInstance->CallCommandHandler(command.c_str(), params, who)) + switch (ServerInstance->CallCommandHandler(command.c_str(), params, who)) { case CMD_INVALID: /* @@ -607,13 +605,15 @@ void TreeSocket::OnTimeout() { if (this->LinkState == CONNECTING) { - this->ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Connection to \002%s\002 timed out.", myhost.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Connection to \002%s\002 timed out.", myhost.c_str()); Utils->DoFailOver(myautoconnect); } } -void TreeSocket::OnClose() +void TreeSocket::Close() { + this->BufferedSocket::Close(); + // Test fix for big fuckup if (this->LinkState != CONNECTED) return; @@ -634,10 +634,10 @@ void TreeSocket::OnClose() if (!quitserver.empty()) { - this->ServerInstance->SNO->WriteToSnoMask('l', "Connection to '\2%s\2' failed.",quitserver.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "Connection to '\2%s\2' failed.",quitserver.c_str()); time_t server_uptime = ServerInstance->Time() - this->age; if (server_uptime) - this->ServerInstance->SNO->WriteToSnoMask('l', "Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str()); } } diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp index b7c13b5f8..0f0e75a1d 100644 --- a/src/modules/m_spanningtree/uid.cpp +++ b/src/modules/m_spanningtree/uid.cpp @@ -64,9 +64,9 @@ bool TreeSocket::ParseUID(const std::string &source, parameterlist ¶ms) } /* check for collision */ - user_hash::iterator iter = this->ServerInstance->Users->clientlist->find(params[2]); + user_hash::iterator iter = ServerInstance->Users->clientlist->find(params[2]); - if (iter != this->ServerInstance->Users->clientlist->end()) + if (iter != ServerInstance->Users->clientlist->end()) { /* * Nick collision. @@ -87,19 +87,19 @@ bool TreeSocket::ParseUID(const std::string &source, parameterlist ¶ms) User* _new = NULL; try { - _new = new User(this->ServerInstance, params[0]); + _new = new User(ServerInstance, params[0]); } catch (...) { this->SendError("Protocol violation - Duplicate UUID '" + params[0] + "' on introduction of new user"); return false; } - (*(this->ServerInstance->Users->clientlist))[params[2]] = _new; + (*(ServerInstance->Users->clientlist))[params[2]] = _new; _new->SetFd(FD_MAGIC_NUMBER); _new->nick.assign(params[2], 0, MAXBUF); _new->host.assign(params[3], 0, 64); _new->dhost.assign(params[4], 0, 64); - _new->server = this->ServerInstance->FindServerNamePtr(remoteserver->GetName().c_str()); + _new->server = ServerInstance->FindServerNamePtr(remoteserver->GetName().c_str()); _new->ident.assign(params[5], 0, MAXBUF); _new->fullname.assign(params[params.size() - 1], 0, MAXBUF); _new->registered = REG_ALL; @@ -164,11 +164,11 @@ bool TreeSocket::ParseUID(const std::string &source, parameterlist ¶ms) bool dosend = true; - if ((this->Utils->quiet_bursts && remoteserver->bursting) || this->ServerInstance->SilentULine(_new->server)) + if ((this->Utils->quiet_bursts && remoteserver->bursting) || ServerInstance->SilentULine(_new->server)) dosend = false; if (dosend) - this->ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]", _new->server, _new->nick.c_str(), _new->ident.c_str(), _new->host.c_str(), _new->GetIPString(), _new->fullname.c_str()); + ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]", _new->server, _new->nick.c_str(), _new->ident.c_str(), _new->host.c_str(), _new->GetIPString(), _new->fullname.c_str()); params[params.size() - 1] = ":" + params[params.size() - 1]; Utils->DoOneToAllButSender(source, "UID", params, source); diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index b37aecc4b..8d3c55758 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -49,19 +49,18 @@ void ServerSocketListener::OnAcceptReady(int newsock) if (!found) { - this->ServerInstance->SNO->WriteToSnoMask('l', "Server connection from %s denied (no link blocks with that IP address)", ip); + ServerInstance->SNO->WriteToSnoMask('l', "Server connection from %s denied (no link blocks with that IP address)", ip); ServerInstance->SE->Close(newsock); return; } } - if (this->GetIOHook()) - { - this->GetIOHook()->OnRawSocketAccept(newsock, &client, &server); - } + /* we don't need to do anything with the pointer, creating it stores it in the necessary places */ + TreeSocket* ts = new TreeSocket(Utils, newsock, ip, NULL, Hook); + + if (Hook) + Hook->OnStreamSocketAccept(ts, &client, &server); - /* we don't need a pointer to this, creating it stores it in the necessary places */ - new TreeSocket(this->Utils, this->ServerInstance, newsock, ip, NULL, this->GetIOHook()); return; } @@ -73,7 +72,7 @@ void ServerSocketListener::OnAcceptReady(int newsock) */ TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) { - if (this->ServerInstance->IsSID(ServerName)) + if (ServerInstance->IsSID(ServerName)) return this->FindServerID(ServerName); server_hash::iterator iter = serverlist.find(ServerName.c_str()); @@ -150,12 +149,10 @@ bool SpanningTreeUtilities::IsServer(const std::string &ServerName) SpanningTreeUtilities::SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* C) : ServerInstance(Instance), Creator(C) { - Bindings.clear(); - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"***** Using SID for hash: %s *****", ServerInstance->Config->GetSID().c_str()); this->TreeRoot = new TreeServer(this, ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc, ServerInstance->Config->GetSID()); - this->ServerUser = new FakeUser(ServerInstance, TreeRoot->GetID()); + ServerUser = new FakeUser(ServerInstance, TreeRoot->GetID()); this->ReadConfiguration(true); } @@ -182,7 +179,6 @@ SpanningTreeUtilities::~SpanningTreeUtilities() ServerUser->uuid = TreeRoot->GetID(); delete TreeRoot; delete ServerUser; - ServerInstance->BufferedSocketCull(); } void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list) @@ -465,7 +461,6 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) { delete Bindings[i]; } - ServerInstance->BufferedSocketCull(); Bindings.clear(); for (int j = 0; j < Conf->Enumerate("bind"); j++) @@ -498,7 +493,7 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) } if (!transport.empty()) - listener->AddIOHook(hooks[transport.c_str()]); + listener->Hook = hooks[transport.c_str()]; Bindings.push_back(listener); } @@ -656,7 +651,7 @@ void SpanningTreeUtilities::DoFailOver(Autoconnect* x) { if (x->FailOver == x->Server) { - this->ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Server.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Server.c_str()); return; } Link* TryThisOne = this->FindLink(x->FailOver.c_str()); @@ -669,13 +664,13 @@ void SpanningTreeUtilities::DoFailOver(Autoconnect* x) } else { - this->ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Server.c_str(), TryThisOne->Name.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Server.c_str(), TryThisOne->Name.c_str()); Creator->ConnectServer(TryThisOne, NULL); } } else { - this->ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Server.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Server.c_str()); } } } diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index 09c707131..1bdf127d8 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -47,8 +47,11 @@ class ServerSocketListener : public ListenSocketBase ServerSocketListener(InspIRCd* Instance, SpanningTreeUtilities *u, int port, char* addr) : ListenSocketBase(Instance, port, addr) { this->Utils = u; + Hook = NULL; } + Module* Hook; + virtual void OnAcceptReady(int nfd); }; diff --git a/src/modules/m_spanningtree/whois.cpp b/src/modules/m_spanningtree/whois.cpp index f12a7f109..79e2d7355 100644 --- a/src/modules/m_spanningtree/whois.cpp +++ b/src/modules/m_spanningtree/whois.cpp @@ -28,13 +28,13 @@ bool TreeSocket::Whois(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 1) return true; - User* u = this->ServerInstance->FindNick(prefix); + User* u = ServerInstance->FindNick(prefix); if (u) { // an incoming request if (params.size() == 1) { - User* x = this->ServerInstance->FindNick(params[0]); + User* x = ServerInstance->FindNick(params[0]); if ((x) && (IS_LOCAL(x))) { char signon[MAXBUF]; @@ -58,7 +58,7 @@ bool TreeSocket::Whois(const std::string &prefix, parameterlist ¶ms) else if (params.size() == 3) { std::string who_did_the_whois = params[0]; - User* who_to_send_to = this->ServerInstance->FindNick(who_did_the_whois); + User* who_to_send_to = ServerInstance->FindNick(who_did_the_whois); if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) { // an incoming reply to a whois we sent out diff --git a/src/socket.cpp b/src/socket.cpp index ccae48a6d..cc9cb79b9 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -273,7 +273,7 @@ std::string irc::sockets::satouser(const irc::sockets::sockaddrs* sa) { return std::string(buffer); } -int irc::sockets::sa_size(irc::sockets::sockaddrs& sa) +int irc::sockets::sa_size(const irc::sockets::sockaddrs& sa) { if (sa.sa.sa_family == AF_INET) return sizeof(sa.in4); diff --git a/src/socketengine.cpp b/src/socketengine.cpp index af2f1b169..c0ae3f278 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -43,35 +43,7 @@ EventHandler::EventHandler() { - this->IOHook = NULL; -} - -bool EventHandler::AddIOHook(Module *IOHooker) -{ - if (this->IOHook) - return false; - - this->IOHook = IOHooker; - return true; -} - -bool EventHandler::DelIOHook() -{ - if (!this->IOHook) - return false; - - this->IOHook = NULL; - return true; -} - -Module *EventHandler::GetIOHook() -{ - return this->IOHook; -} - -int EventHandler::GetFd() -{ - return this->fd; + fd = -1; } void EventHandler::SetFd(int FD) @@ -79,21 +51,7 @@ void EventHandler::SetFd(int FD) this->fd = FD; } -bool EventHandler::Readable() -{ - return true; -} - -bool EventHandler::Writeable() -{ - return false; -} - -void SocketEngine::WantWrite(EventHandler* eh) -{ -} - -SocketEngine::SocketEngine(InspIRCd* Instance) : ServerInstance(Instance) +SocketEngine::SocketEngine() { TotalEvents = WriteEvents = ReadEvents = ErrorEvents = 0; lastempty = ServerInstance->Time(); @@ -104,11 +62,6 @@ SocketEngine::~SocketEngine() { } -bool SocketEngine::AddFd(EventHandler* eh) -{ - return true; -} - bool SocketEngine::HasFd(int fd) { if ((fd < 0) || (fd > MAX_DESCRIPTORS)) @@ -123,11 +76,6 @@ EventHandler* SocketEngine::GetRef(int fd) return ref[fd]; } -bool SocketEngine::DelFd(EventHandler* eh, bool force) -{ - return true; -} - int SocketEngine::GetMaxFds() { return 0; @@ -143,11 +91,6 @@ int SocketEngine::DispatchEvents() return 0; } -std::string SocketEngine::GetName() -{ - return "misconfigured"; -} - bool SocketEngine::BoundsCheckFd(EventHandler* eh) { if (!eh) diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp index 1be0d7cd2..7fed6f250 100644 --- a/src/socketengines/socketengine_epoll.cpp +++ b/src/socketengines/socketengine_epoll.cpp @@ -16,7 +16,7 @@ #include "socketengines/socketengine_epoll.h" #include -EPollEngine::EPollEngine(InspIRCd* Instance) : SocketEngine(Instance) +EPollEngine::EPollEngine() { MAX_DESCRIPTORS = 0; // This is not a maximum, just a hint at the eventual number of sockets that may be polled. @@ -45,7 +45,7 @@ EPollEngine::~EPollEngine() delete[] events; } -bool EPollEngine::AddFd(EventHandler* eh) +bool EPollEngine::AddFd(EventHandler* eh, bool writeFirst) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) @@ -68,7 +68,7 @@ bool EPollEngine::AddFd(EventHandler* eh) struct epoll_event ev; memset(&ev,0,sizeof(ev)); - eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT; + ev.events = writeFirst ? EPOLLOUT : EPOLLIN; ev.data.fd = fd; int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev); if (i < 0) @@ -107,7 +107,6 @@ bool EPollEngine::DelFd(EventHandler* eh, bool force) struct epoll_event ev; memset(&ev,0,sizeof(ev)); - eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT; ev.data.fd = fd; int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev); diff --git a/src/socketengines/socketengine_iocp.cpp b/src/socketengines/socketengine_iocp.cpp index ee2e5afa1..3c3181909 100644 --- a/src/socketengines/socketengine_iocp.cpp +++ b/src/socketengines/socketengine_iocp.cpp @@ -15,7 +15,7 @@ #include "exitcodes.h" #include -IOCPEngine::IOCPEngine(InspIRCd * Instance) : SocketEngine(Instance) +IOCPEngine::IOCPEngine() { MAX_DESCRIPTORS = 10240; @@ -47,7 +47,7 @@ IOCPEngine::~IOCPEngine() delete[] ref; } -bool IOCPEngine::AddFd(EventHandler* eh) +bool IOCPEngine::AddFd(EventHandler* eh, bool writeFirst) { /* Does it at least look valid? */ if (!eh) @@ -92,7 +92,7 @@ bool IOCPEngine::AddFd(EventHandler* eh) ServerInstance->Logs->Log("SOCKET",DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", *fake_fd, eh->GetFd(), eh); /* post a write event if there is data to be written */ - if(eh->Writeable()) + if(writeFirst) WantWrite(eh); /* we're all good =) */ diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp index bf09eaf74..cbe3e959d 100644 --- a/src/socketengines/socketengine_kqueue.cpp +++ b/src/socketengines/socketengine_kqueue.cpp @@ -19,7 +19,7 @@ #include "socketengines/socketengine_kqueue.h" #include -KQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance) +KQueueEngine::KQueueEngine() { MAX_DESCRIPTORS = 0; this->RecoverFromFork(); @@ -54,7 +54,7 @@ KQueueEngine::~KQueueEngine() delete[] ke_list; } -bool KQueueEngine::AddFd(EventHandler* eh) +bool KQueueEngine::AddFd(EventHandler* eh, bool writeFirst) { int fd = eh->GetFd(); @@ -79,7 +79,7 @@ bool KQueueEngine::AddFd(EventHandler* eh) return false; } - if (!eh->Readable()) { + if (writeFirst) { // ...and sometimes want to write WantWrite(eh); } diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index cee6a90cb..6d5ddb9f5 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -19,7 +19,7 @@ #include #endif -PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance) +PollEngine::PollEngine() { // Poll requires no special setup (which is nice). CurrentSetSize = 0; @@ -39,7 +39,7 @@ PollEngine::~PollEngine() delete[] events; } -bool PollEngine::AddFd(EventHandler* eh) +bool PollEngine::AddFd(EventHandler* eh, bool writeFirst) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) @@ -65,13 +65,13 @@ bool PollEngine::AddFd(EventHandler* eh) fd_mappings[fd] = index; ref[index] = eh; events[index].fd = fd; - if (eh->Readable()) + if (writeFirst) { - events[index].events = POLLIN; + events[index].events = POLLOUT; } else { - events[index].events = POLLOUT; + events[index].events = POLLIN; } ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[fd].events, index); diff --git a/src/socketengines/socketengine_ports.cpp b/src/socketengines/socketengine_ports.cpp index 5efa545b0..eb08839d0 100644 --- a/src/socketengines/socketengine_ports.cpp +++ b/src/socketengines/socketengine_ports.cpp @@ -17,7 +17,7 @@ #include "socketengines/socketengine_ports.h" #include -PortsEngine::PortsEngine(InspIRCd* Instance) : SocketEngine(Instance) +PortsEngine::PortsEngine() { MAX_DESCRIPTORS = 0; EngineHandle = port_create(); @@ -44,7 +44,7 @@ PortsEngine::~PortsEngine() delete[] events; } -bool PortsEngine::AddFd(EventHandler* eh) +bool PortsEngine::AddFd(EventHandler* eh, bool writeFirst) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) @@ -57,7 +57,7 @@ bool PortsEngine::AddFd(EventHandler* eh) return false; ref[fd] = eh; - port_associate(EngineHandle, PORT_SOURCE_FD, fd, eh->Readable() ? POLLRDNORM : POLLWRNORM, eh); + port_associate(EngineHandle, PORT_SOURCE_FD, fd, writeFirst ? POLLWRNORM : POLLRDNORM, eh); ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); CurrentSetSize++; diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp index 8c41df11b..7f6a4e283 100644 --- a/src/socketengines/socketengine_select.cpp +++ b/src/socketengines/socketengine_select.cpp @@ -18,7 +18,7 @@ #include "socketengines/socketengine_select.h" -SelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance) +SelectEngine::SelectEngine() { MAX_DESCRIPTORS = FD_SETSIZE; EngineHandle = 0; @@ -34,7 +34,7 @@ SelectEngine::~SelectEngine() delete[] ref; } -bool SelectEngine::AddFd(EventHandler* eh) +bool SelectEngine::AddFd(EventHandler* eh, bool writeFirst) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) @@ -50,6 +50,8 @@ bool SelectEngine::AddFd(EventHandler* eh) ref[fd] = eh; CurrentSetSize++; + writeable[eh->GetFd()] = writeFirst; + ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); return true; } @@ -101,16 +103,11 @@ int SelectEngine::DispatchEvents() /* Populate the select FD set (this is why select sucks compared to epoll, kqueue, IOCP) */ for (std::set::iterator a = fds.begin(); a != fds.end(); a++) { - if (ref[*a]->Readable()) - /* Read notifications */ - FD_SET (*a, &rfdset); - else - /* Write notifications */ - FD_SET (*a, &wfdset); - /* Explicitly one-time writeable */ if (writeable[*a]) FD_SET (*a, &wfdset); + else + FD_SET (*a, &rfdset); /* All sockets must receive error notifications regardless */ FD_SET (*a, &errfdset); diff --git a/src/stats.cpp b/src/stats.cpp index 40ee40b18..02cfeaa7c 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -254,7 +254,7 @@ void InspIRCd::DoStats(char statschar, User* user, string_list &results) for (std::vector::iterator n = this->Users->local_users.begin(); n != this->Users->local_users.end(); n++) { User* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); } break; @@ -264,7 +264,7 @@ void InspIRCd::DoStats(char statschar, User* user, string_list &results) for (std::vector::iterator n = this->Users->local_users.begin(); n != this->Users->local_users.end(); n++) { User* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); } break; diff --git a/src/threadengines/threadengine_pthread.cpp b/src/threadengines/threadengine_pthread.cpp index 6e32634c5..a4a47f8fa 100644 --- a/src/threadengines/threadengine_pthread.cpp +++ b/src/threadengines/threadengine_pthread.cpp @@ -65,8 +65,7 @@ class ThreadSignalSocket : public BufferedSocket { SocketThread* parent; public: - ThreadSignalSocket(SocketThread* p, InspIRCd* SI, int newfd) : - BufferedSocket(SI, newfd, const_cast("0.0.0.0")), parent(p) {} + ThreadSignalSocket(SocketThread* p, int newfd) : BufferedSocket(newfd), parent(p) {} ~ThreadSignalSocket() { @@ -77,13 +76,14 @@ class ThreadSignalSocket : public BufferedSocket eventfd_write(fd, 1); } - virtual bool OnDataReady() + void OnDataReady() { - eventfd_t data; - if (eventfd_read(fd, &data)) - return false; + recvq.clear(); parent->OnNotify(); - return true; + } + + void OnError(BufferedSocketError) + { } }; @@ -92,7 +92,7 @@ SocketThread::SocketThread(InspIRCd* SI) int fd = eventfd(0, O_NONBLOCK); if (fd < 0) throw new CoreException("Could not create pipe " + std::string(strerror(errno))); - signal.sock = new ThreadSignalSocket(this, SI, fd); + signal.sock = new ThreadSignalSocket(this, fd); } #else @@ -101,8 +101,8 @@ class ThreadSignalSocket : public BufferedSocket SocketThread* parent; int send_fd; public: - ThreadSignalSocket(SocketThread* p, InspIRCd* SI, int recvfd, int sendfd) : - BufferedSocket(SI, recvfd, const_cast("0.0.0.0")), parent(p), send_fd(sendfd) {} + ThreadSignalSocket(SocketThread* p, int recvfd, int sendfd) : + BufferedSocket(recvfd), parent(p), send_fd(sendfd) {} ~ThreadSignalSocket() { @@ -115,13 +115,14 @@ class ThreadSignalSocket : public BufferedSocket write(send_fd, &dummy, 1); } - virtual bool OnDataReady() + void OnDataReady() { - char data; - if (read(this->fd, &data, 1) <= 0) - return false; + recvq.clear(); parent->OnNotify(); - return true; + } + + void OnError(BufferedSocketError) + { } }; @@ -130,7 +131,7 @@ SocketThread::SocketThread(InspIRCd* SI) int fds[2]; if (pipe(fds)) throw new CoreException("Could not create pipe " + std::string(strerror(errno))); - signal.sock = new ThreadSignalSocket(this, SI, fds[0], fds[1]); + signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]); } #endif diff --git a/src/threadengines/threadengine_win32.cpp b/src/threadengines/threadengine_win32.cpp index 5c62b5081..fab75699e 100644 --- a/src/threadengines/threadengine_win32.cpp +++ b/src/threadengines/threadengine_win32.cpp @@ -55,20 +55,15 @@ class ThreadSignalSocket : public BufferedSocket { SocketThread* parent; public: - ThreadSignalSocket(SocketThread* t, InspIRCd* SI, int newfd, const char* ip) - : BufferedSocket(SI, newfd, ip), parent(t) + ThreadSignalSocket(SocketThread* t, int newfd) + : BufferedSocket(newfd), parent(t) { } - virtual bool OnDataReady() + void OnDataReady() { - char data = 0; - if (ServerInstance->SE->Recv(this, &data, 1, 0) > 0) - { - parent->OnNotify(); - return true; - } - return false; + recvq.clear(); + parent->OnNotify(); } }; @@ -92,7 +87,7 @@ SocketThread::SocketThread(InspIRCd* SI) int nfd = accept(listenFD); if (nfd < 0) throw CoreException("Could not create ITC pipe"); - new ThreadSignalSocket(parent, ServerInstance, nfd, "127.0.0.1"); + new ThreadSignalSocket(parent, nfd); closesocket(listenFD); SI->SE->Blocking(connFD); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index b9eff5a39..6d04bdff7 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -46,7 +46,7 @@ void UserManager::AddUser(InspIRCd* Instance, int socket, ClientListenSocket* vi { try { - New->GetIOHook()->OnRawSocketAccept(socket, client, server); + New->GetIOHook()->OnStreamSocketAccept(New, client, server); } catch (CoreException& modexcept) { @@ -201,24 +201,18 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char FOREACH_MOD_I(ServerInstance,I_OnUserDisconnect,OnUserDisconnect(user)); - user->UpdateNickHash(user->uuid.c_str()); - - user_hash::iterator iter = this->clientlist->find(user->uuid); - if (user->registered != REG_ALL) if (ServerInstance->Users->unregistered_count) ServerInstance->Users->unregistered_count--; if (IS_LOCAL(user)) { - if (!user->sendq.empty()) - user->FlushWriteBuf(); - + user->DoWrite(); if (user->GetIOHook()) { try { - user->GetIOHook()->OnRawSocketClose(user->GetFd()); + user->GetIOHook()->OnStreamSocketClose(user); } catch (CoreException& modexcept) { @@ -227,7 +221,9 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char } ServerInstance->SE->DelFd(user); - user->CloseSocket(); + user->Close(); + // user->Close() will set fd to -1; this breaks IS_LOCAL. Fix + user->SetFd(INT_MAX); } /* @@ -255,19 +251,12 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char user->AddToWhoWas(); } + user_hash::iterator iter = this->clientlist->find(user->nick); + if (iter != this->clientlist->end()) this->clientlist->erase(iter); else ServerInstance->Logs->Log("USERS", DEBUG, "iter == clientlist->end, can't remove them from hash... problematic.."); - - if (IS_LOCAL(user)) - { - std::vector::iterator x = find(local_users.begin(),local_users.end(),user); - if (x != local_users.end()) - local_users.erase(x); - else - ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); - } } diff --git a/src/userprocess.cpp b/src/userprocess.cpp index 4fcf87f66..b150f2828 100644 --- a/src/userprocess.cpp +++ b/src/userprocess.cpp @@ -36,102 +36,6 @@ void FloodQuitUserHandler::Call(User* current) } } -void ProcessUserHandler::Call(User* cu) -{ - int result = EAGAIN; - - if (cu->GetFd() == FD_MAGIC_NUMBER) - return; - - char* ReadBuffer = Server->GetReadBuffer(); - - if (cu->GetIOHook()) - { - int result2 = 0; - int MOD_RESULT = 0; - - try - { - MOD_RESULT = cu->GetIOHook()->OnRawSocketRead(cu->GetFd(), ReadBuffer, Server->Config->NetBufferSize, result2); - } - catch (CoreException& modexcept) - { - Server->Logs->Log("USERS",DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - } - - if (MOD_RESULT < 0) - { - result = -EAGAIN; - } - else - { - result = result2; - } - } - else - { - result = cu->ReadData(ReadBuffer, Server->Config->NetBufferSize); - } - - if ((result) && (result != -EAGAIN)) - { - User *current; - int currfd; - - Server->stats->statsRecv += result; - /* - * perform a check on the raw buffer as an array (not a string!) to remove - * character 0 which is illegal in the RFC - replace them with spaces. - */ - - for (int checker = 0; checker < result; checker++) - { - if (ReadBuffer[checker] == 0) - ReadBuffer[checker] = ' '; - } - - if (result > 0) - ReadBuffer[result] = '\0'; - - current = cu; - currfd = current->GetFd(); - - // add the data to the users buffer - if (result > 0) - { - if (!current->AddBuffer(ReadBuffer)) - { - // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good. - Server->FloodQuitUser(current); - return; - } - - /* If user is over penalty, dont process here, just build up */ - if (current->Penalty < 10) - Server->Parser->DoLines(current); - - return; - } - - if ((result == -1) && (errno != EAGAIN) && (errno != EINTR)) - { - Server->Users->QuitUser(cu, errno ? strerror(errno) : "EOF from client"); - return; - } - } - - // result EAGAIN means nothing read - else if ((result == EAGAIN) || (result == -EAGAIN)) - { - /* do nothing */ - } - else if (result == 0) - { - Server->Users->QuitUser(cu, "Connection closed"); - return; - } -} - /** * This function is called once a second from the mainloop. * It is intended to do background checking on all the user structs, e.g. @@ -154,8 +58,12 @@ void InspIRCd::DoBackgroundUserStuff() if (curr->Penalty) { curr->Penalty--; - if (curr->Penalty < 10) - Parser->DoLines(curr, true); + curr->OnDataReady(); + } + + if (curr->getSendQSize() == 0) + { + FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(curr)); } switch (curr->registered) diff --git a/src/users.cpp b/src/users.cpp index fd0c168d9..5d6b1a01a 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -216,12 +216,8 @@ User::User(InspIRCd* Instance, const std::string &uid) fd = -1; server_sa.sa.sa_family = AF_UNSPEC; client_sa.sa.sa_family = AF_UNSPEC; - recvq.clear(); - sendq.clear(); MyClass = NULL; AllowedPrivs = AllowedOperCommands = NULL; - chans.clear(); - invites.clear(); if (uid.empty()) uuid.assign(Instance->GetUID(), 0, UUID_LENGTH - 1); @@ -309,15 +305,6 @@ const std::string& User::MakeHostIP() return this->cached_hostip; } -void User::CloseSocket() -{ - if (this->fd > -1) - { - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); - } -} - const std::string User::GetFullHost() { if (!this->cached_fullhost.empty()) @@ -352,21 +339,6 @@ char* User::MakeWildHost() return nresult; } -int User::ReadData(void* buffer, size_t size) -{ - if (IS_LOCAL(this)) - { -#ifndef WIN32 - return read(this->fd, buffer, size); -#else - return recv(this->fd, (char*)buffer, size, 0); -#endif - } - else - return 0; -} - - const std::string User::GetFullRealHost() { if (!this->cached_fullrealhost.empty()) @@ -540,123 +512,60 @@ bool User::HasPrivPermission(const std::string &privstr, bool noisy) return false; } -bool User::AddBuffer(const std::string &a) +void User::OnDataReady() { - std::string::size_type start = 0; - std::string::size_type i = a.find('\r'); - - /* - * The old implementation here took a copy, and rfind() on \r, removing as it found them, before - * copying a second time onto the recvq. That's ok, but involves three copies minimum (recv() to buffer, - * buffer to here, here to recvq) - The new method now copies twice (recv() to buffer, buffer to recvq). - * - * We use find() instead of rfind() for clarity, however unlike the old code, our scanning of the string is - * contiguous: as we specify a startpoint, we never see characters we have scanned previously, making this - * marginally faster in cases with a number of \r hidden early on in the buffer. - * - * How it works: - * Start at first pos of string, find first \r, append everything in the chunk (excluding \r) to recvq. Set - * i ahead of the \r, search for next \r, add next chunk to buffer... repeat. - * -- w00t (7 may, 2008) - */ - if (i == std::string::npos) - { - // no \r that we need to dance around, just add to buffer - recvq.append(a); - } - else - { - // While we can find the end of a chunk to add - while (i != std::string::npos) - { - // Append the chunk that we have - recvq.append(a, start, (i - start)); - - // Start looking for the next one - start = i + 1; - i = a.find('\r', start); - } - - if (start != a.length()) - { - /* - * This is here to catch a corner case when we get something like: - * NICK w0 - * 0t\r\nU - * SER ... - * in successive calls to us. - * - * Without this conditional, the 'U' on the second case will be dropped, - * which is most *certainly* not the behaviour we want! - * -- w00t - */ - recvq.append(a, start, (a.length() - start)); - } - } + if (quitting) + return; - if (this->MyClass && !this->HasPrivPermission("users/flood/increased-buffers") && recvq.length() > this->MyClass->GetRecvqMax()) + if (MyClass && !HasPrivPermission("users/flood/increased-buffers") && recvq.length() > MyClass->GetRecvqMax()) { ServerInstance->Users->QuitUser(this, "RecvQ exceeded"); - ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick.c_str(),(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax()); - return false; + ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu", + nick.c_str(), (unsigned long)recvq.length(), MyClass->GetRecvqMax()); } - return true; -} - -bool User::BufferIsReady() -{ - return (recvq.find('\n') != std::string::npos); -} - -void User::ClearBuffer() -{ - recvq.clear(); -} - -std::string User::GetBuffer() -{ - try + while (this->Penalty < 10) { - if (recvq.empty()) - return ""; - - /* Strip any leading \r or \n off the string. - * Usually there are only one or two of these, - * so its is computationally cheap to do. - */ - std::string::iterator t = recvq.begin(); - while (t != recvq.end() && (*t == '\r' || *t == '\n')) - { - recvq.erase(t); - t = recvq.begin(); - } - - for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++) + std::string line; + line.reserve(MAXBUF); + std::string::size_type qpos = 0; + while (qpos < recvq.length()) { - /* Find the first complete line, return it as the - * result, and leave the recvq as whats left - */ - if (*x == '\n') + char c = recvq[qpos++]; + switch (c) { - std::string ret = std::string(recvq.begin(), x); - recvq.erase(recvq.begin(), x + 1); - return ret; + case '\0': + c = ' '; + break; + case '\r': + continue; + case '\n': + goto eol_found; } + if (line.length() < MAXBUF - 2) + line.push_back(c); } - return ""; - } + // if we got here, the recvq ran out before we found a newline + return; +eol_found: + // just found a newline. Terminate the string, and pull it out of recvq + recvq = recvq.substr(qpos); - catch (...) - { - ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::GetBuffer()"); - return ""; + // TODO should this be moved to when it was inserted in recvq? + ServerInstance->stats->statsRecv += qpos; + this->bytes_in += qpos; + this->cmds_in++; + + ServerInstance->Parser->ProcessBuffer(line, this); } } void User::AddWriteBuf(const std::string &data) { - if (!this->quitting && this->MyClass && !this->HasPrivPermission("users/flood/increased-buffers") && sendq.length() + data.length() > this->MyClass->GetSendqMax()) + // Don't bother sending text to remote users! + if (IS_REMOTE(this)) + return; + if (!quitting && MyClass && getSendQSize() + data.length() > MyClass->GetSendqMax() && !HasPrivPermission("users/flood/increased-buffers")) { /* * Fix by brain - Set the error text BEFORE calling, because @@ -664,66 +573,36 @@ void User::AddWriteBuf(const std::string &data) * to repeatedly add the text to the sendq! */ ServerInstance->Users->QuitUser(this, "SendQ exceeded"); - ServerInstance->SNO->WriteToSnoMask('a', "User %s SendQ of %lu exceeds connect class maximum of %lu",this->nick.c_str(),(unsigned long int)sendq.length() + data.length(),this->MyClass->GetSendqMax()); + ServerInstance->SNO->WriteToSnoMask('a', "User %s SendQ of %lu exceeds connect class maximum of %lu", + nick.c_str(), (unsigned long)getSendQSize() + data.length(), MyClass->GetSendqMax()); return; } // We still want to append data to the sendq of a quitting user, // e.g. their ERROR message that says 'closing link' - if (data.length() > MAXBUF - 2) /* MAXBUF has a value of 514, to account for line terminators */ - sendq.append(data.substr(0,MAXBUF - 4)).append("\r\n"); /* MAXBUF-4 = 510 */ - else - sendq.append(data); + WriteData(data); } -// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it) -void User::FlushWriteBuf() +void User::OnError(BufferedSocketError) { - if (this->fd == FD_MAGIC_NUMBER) - { - sendq.clear(); - return; - } + ServerInstance->Users->QuitUser(this, getError()); +} - if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER)) +void User::cull() +{ + if (!quitting) + ServerInstance->Users->QuitUser(this, "Culled without QuitUser"); + if (IS_LOCAL(this)) { - int old_sendq_length = sendq.length(); - int n_sent = ServerInstance->SE->Send(this, this->sendq.data(), this->sendq.length(), 0); + if (fd != INT_MAX) + Close(); - if (n_sent == -1) - { - if (errno == EAGAIN) - { - /* The socket buffer is full. This isnt fatal, - * try again later. - */ - ServerInstance->SE->WantWrite(this); - } - else - { - /* Fatal error, set write error and bail */ - ServerInstance->Users->QuitUser(this, errno ? strerror(errno) : "Write error"); - return; - } - } + std::vector::iterator x = find(ServerInstance->Users->local_users.begin(),ServerInstance->Users->local_users.end(),this); + if (x != ServerInstance->Users->local_users.end()) + ServerInstance->Users->local_users.erase(x); else - { - /* advance the queue */ - if (n_sent) - this->sendq = this->sendq.substr(n_sent); - /* update the user's stats counters */ - this->bytes_out += n_sent; - this->cmds_out++; - if (n_sent != old_sendq_length) - ServerInstance->SE->WantWrite(this); - } - } - - /* note: NOT else if! */ - if (this->sendq.empty()) - { - FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(this)); + ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); } } @@ -1191,35 +1070,29 @@ bool User::SetClientIP(const char* sip) return irc::sockets::aptosa(sip, 0, &client_sa); } +static std::string wide_newline("\r\n"); + void User::Write(const std::string& text) { if (!ServerInstance->SE->BoundsCheckFd(this)) return; - ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"C[%d] O %s", this->GetFd(), text.c_str()); - - if (this->GetIOHook()) + if (text.length() > MAXBUF - 2) { - /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to - * implement their own buffering mechanisms - */ - try - { - this->GetIOHook()->OnRawSocketWrite(this->fd, text.data(), text.length()); - this->GetIOHook()->OnRawSocketWrite(this->fd, "\r\n", 2); - } - catch (CoreException& modexcept) - { - ServerInstance->Logs->Log("USEROUTPUT", DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - } - } - else - { - this->AddWriteBuf(text); - this->AddWriteBuf("\r\n"); + // this should happen rarely or never. Crop the string at 512 and try again. + std::string try_again = text.substr(0, MAXBUF - 2); + Write(try_again); + return; } + + ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"C[%d] O %s", this->GetFd(), text.c_str()); + + this->AddWriteBuf(text); + this->AddWriteBuf(wide_newline); + ServerInstance->stats->statsSent += text.length() + 2; - ServerInstance->SE->WantWrite(this); + this->bytes_out += text.length() + 2; + this->cmds_out++; } /** Write() @@ -1904,25 +1777,6 @@ void User::ShowRULES() this->WriteNumeric(RPL_RULESEND, "%s :End of RULES command.",this->nick.c_str()); } -void User::HandleEvent(EventType et, int errornum) -{ - if (this->quitting) // drop everything, user is due to be quit - return; - - switch (et) - { - case EVENT_READ: - ServerInstance->ProcessUser(this); - break; - case EVENT_WRITE: - this->FlushWriteBuf(); - break; - case EVENT_ERROR: - ServerInstance->Users->QuitUser(this, errornum ? strerror(errornum) : "Client closed the connection"); - break; - } -} - void User::IncreasePenalty(int increase) { this->Penalty += increase; -- 2.39.2