1 /* +------------------------------------+
\r * | Inspire Internet Relay Chat Daemon |
\r * +------------------------------------+
\r *
\r * InspIRCd: (C) 2002-2007 InspIRCd Development Team
\r * See: http://www.inspircd.org/wiki/index.php/Credits
\r *
\r * This program is free but copyrighted software; see
\r * the file COPYING for details.
\r *
\r * ---------------------------------------------------
\r */
\r\r#ifndef __INSP_SOCKET_H__
\r#define __INSP_SOCKET_H__
\r\r#include <sstream>
\r#include <string>
\r#include <deque>
\r#include "dns.h"
\r#include "inspircd_config.h"
\r#include "socket.h"
\r#include "inspsocket.h"
\r#include "timer.h"
\r\r/**
\r * States which a socket may be in
\r */
\renum InspSocketState
\r{
\r /** Socket disconnected */
\r I_DISCONNECTED,
\r /** Socket connecting */
\r I_CONNECTING,
\r /** Socket fully connected */
\r I_CONNECTED,
\r /** Socket listening for connections */
\r I_LISTENING,
\r /** Socket has an error */
\r I_ERROR
\r};
\r\r/**
\r * Error types which a socket may exhibit
\r */
\renum InspSocketError
\r{
\r /** Socket connect timed out */
\r I_ERR_TIMEOUT,
\r /** Socket could not be created */
\r I_ERR_SOCKET,
\r /** Socket could not connect (refused) */
\r I_ERR_CONNECT,
\r /** Socket could not bind to local port/ip */
\r I_ERR_BIND,
\r /** Socket could not reslve host (depreciated) */
\r I_ERR_RESOLVE,
\r /** Socket could not write data */
\r I_ERR_WRITE,
\r /** No more file descriptors left to create socket! */
\r I_ERR_NOMOREFDS
\r};
\r\r/* Required forward declarations */
\rclass InspSocket;
\rclass InspIRCd;
\r\rusing irc::sockets::insp_sockaddr;
\rusing irc::sockets::insp_inaddr;
\rusing irc::sockets::insp_ntoa;
\rusing irc::sockets::insp_aton;
\r\r/** Used to time out socket connections
\r */
\rclass CoreExport SocketTimeout : public InspTimer
\r{
\r private:
\r /** InspSocket the class is attached to
\r */
\r InspSocket* sock;
\r /** Server instance creating the timeout class
\r */
\r InspIRCd* ServerInstance;
\r /** File descriptor of class this is attached to
\r */
\r int sfd;
\r public:
\r /** Create a socket timeout class
\r * @param fd File descriptor of InspSocket
\r * @pram Instance server instance to attach to
\r * @param thesock InspSocket to attach to
\r * @param secs_from_now Seconds from now to time out
\r * @param now The current time
\r */
\r SocketTimeout(int fd, InspIRCd* Instance, InspSocket* thesock, long secs_from_now, time_t now) : InspTimer(secs_from_now, now), sock(thesock), ServerInstance(Instance), sfd(fd) { };
\r /** Handle tick event
\r */
\r virtual void Tick(time_t now);
\r};
\r\r/**
\r * InspSocket is an extendable socket class which modules
\r * can use for TCP socket support. It is fully integrated
\r * into InspIRCds socket loop and attaches its sockets to
\r * the core's instance of the SocketEngine class, meaning
\r * that any sockets you create have the same power and
\r * abilities as a socket created by the core itself.
\r * To use InspSocket, you must inherit a class from it,
\r * and use the InspSocket constructors to establish connections
\r * and bindings.
\r */
\rclass CoreExport InspSocket : public EventHandler
\r{
\r public:
\r\r /**
\r * Bind IP
\r */
\r std::string cbindip;
\r\r /**
\r * Is hooked by a module for low level IO
\r */
\r bool IsIOHooked;
\r\r /**
\r * Instance we were created by
\r */
\r InspIRCd* Instance;
\r\r /**
\r * Timeout class or NULL
\r */
\r SocketTimeout* Timeout;
\r\r /**
\r * Timeout length
\r */
\r unsigned long timeout_val;
\r\r /**
\r * Socket output buffer (binary safe)
\r */
\r std::deque<std::string> outbuffer;
\r\r /**
\r * The hostname connected to
\r */
\r char host[MAXBUF];
\r\r /**
\r * The port connected to, or the port
\r * this socket is listening on
\r */
\r int port;
\r\r /**
\r * The state for this socket, either
\r * listening, connecting, connected
\r * or error.
\r */
\r InspSocketState state;
\r\r /**
\r * This value is true if the
\r * socket has timed out.
\r */
\r bool timeout;
\r \r /**
\r * Socket input buffer, used by read(). The class which
\r * extends InspSocket is expected to implement an extendable
\r * buffer which can grow much larger than 64k,
\r * this buffer is just designed to be temporary storage.
\r * space.
\r */
\r char ibuf[65535];
\r\r /**
\r * The IP address being connected
\r * to stored in string form for
\r * easy retrieval by accessors.
\r */
\r char IP[MAXBUF];
\r\r /**
\r * Used by accept() to indicate the
\r * sizes of the sockaddr_in structures
\r */
\r socklen_t length;
\r\r /** Flushes the write buffer
\r */
\r bool FlushWriteBuffer();
\r\r /** Set the queue sizes
\r * This private method sets the operating system queue
\r * sizes for this socket to 65535 so that it can queue
\r * more information without application-level queueing
\r * which was required in older software.
\r */
\r void SetQueues(int nfd);
\r\r /** When the socket has been marked as closing, this flag
\r * will be set to true, then the next time the socket is
\r * examined, the socket is deleted and closed.
\r */
\r bool ClosePending;
\r\r /** Set to true when we're waiting for a write event.
\r * If this is true and a write event comes in, we
\r * call the write instead of the read method.
\r */
\r bool WaitingForWriteEvent;
\r\r /**
\r * Bind to an address
\r * @param ip IP to bind to
\r * @return True is the binding succeeded
\r */
\r bool BindAddr(const std::string &ip);
\r\r /**
\r * The default constructor does nothing
\r * and should not be used.
\r */
\r InspSocket(InspIRCd* SI);
\r\r /**
\r * This constructor is used to associate
\r * an existing connecting with an InspSocket
\r * class. The given file descriptor must be
\r * valid, and when initialized, the InspSocket
\r * will be set with the given IP address
\r * and placed in CONNECTED state.
\r */
\r InspSocket(InspIRCd* SI, int newfd, const char* ip);
\r\r /**
\r * This constructor is used to create a new
\r * socket, either listening for connections, or an outbound connection to another host.
\r * Note that if you specify a hostname in the 'ipaddr' parameter, this class will not
\r * connect. You must resolve your hostnames before passing them to InspSocket. To do so,
\r * you should use the nonblocking class 'Resolver'.
\r * @param ipaddr The IP to connect to, or bind to
\r * @param port The port number to connect to, or bind to
\r * @param listening true to listen on the given host:port pair, or false to connect to them
\r * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated
\r * @param connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound.
\r * @return On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error.
\r */
\r InspSocket(InspIRCd* SI, const std::string &ipaddr, int port, bool listening, unsigned long maxtime, const std::string &connectbindip = "");
\r\r /**
\r * This method is called when an outbound
\r * connection on your socket is completed.
\r * @return false to abort the connection, true to continue
\r */
\r virtual bool OnConnected();
\r\r /**
\r * This method is called when an error occurs.
\r * A closed socket in itself is not an error,
\r * however errors also generate close events.
\r * @param e The error type which occured
\r */
\r virtual void OnError(InspSocketError e);
\r\r /**
\r * When an established connection is terminated,
\r * the OnDisconnect method is triggered.
\r */
\r virtual int OnDisconnect();
\r\r /**
\r * When there is data waiting to be read on a
\r * socket, the OnDataReady() method is called.
\r * Within this method, you *MUST* call the Read()
\r * method to read any pending data. At its lowest
\r * level, this event is signalled by the core via
\r * the socket engine. If you return false from this
\r * function, the core removes your socket from its
\r * list and erases it from the socket engine, then
\r * calls InspSocket::Close() and deletes it.
\r * @return false to close the socket
\r */
\r virtual bool OnDataReady();
\r\r /**
\r * When it is ok to write to the socket, and a
\r * write event was requested, this method is
\r * triggered. Within this method you should call
\r * write() or send() etc, to send data to the
\r * other end of the socket. Further write events
\r * will not be triggered unless you call WantWrite().
\r * @return false to close the socket
\r */
\r virtual bool OnWriteReady();
\r\r /**
\r * When an outbound connection fails, and the
\r * attempt times out, you will receive this event.
\r * The method will trigger once maxtime seconds are
\r * reached (as given in the constructor) just
\r * before the socket's descriptor is closed.
\r * A failed DNS lookup may cause this event if
\r * the DNS server is not responding, as well as
\r * a failed connect() call, because DNS lookups are
\r * nonblocking as implemented by this class.
\r */
\r virtual void OnTimeout();
\r\r /**
\r * Whenever close() is called, OnClose() will be
\r * called first. Please note that this means
\r * OnClose will be called alongside OnError(),
\r * OnTimeout(), and Close(), and also when
\r * cancelling a listening socket by calling
\r * the destructor indirectly.
\r */
\r virtual void OnClose();
\r\r /**
\r * Reads all pending bytes from the socket
\r * into a char* array which can be up to
\r * 16 kilobytes in length.
\r */
\r virtual char* Read();
\r\r /**
\r * Returns the IP address associated with
\r * this connection, or an empty string if
\r * no IP address exists.
\r */
\r std::string GetIP();
\r\r /**
\r * Writes a std::string to the socket. No carriage
\r * returns or linefeeds are appended to the string.
\r * @param data The data to send
\r */
\r virtual int Write(const std::string &data);
\r\r /**
\r * If your socket is a listening socket, when a new
\r * connection comes in on the socket this method will
\r * be called. Given the new file descriptor in the
\r * parameters, and the IP, it is recommended you copy
\r * them to a new instance of your socket class,
\r * e.g.:
\r *
\r * MySocket* newsocket = new MySocket(newfd,ip);
\r *
\r * Once you have done this, you can then associate the
\r * new socket with the core using Server::AddSocket().
\r */
\r virtual int OnIncomingConnection(int newfd, char* ip);
\r\r /**
\r * Changes the socket's state. The core uses this
\r * to change socket states, and you should not call
\r * it directly.
\r */
\r void SetState(InspSocketState s);
\r\r /**
\r * Call this to receive the next write event
\r * that comes along for this fd to the OnWriteReady
\r * method.
\r */
\r void WantWrite();
\r\r /**
\r * Returns the current socket state.
\r */
\r InspSocketState GetState();
\r\r /**
\r * Only the core should call this function.
\r * When called, it is assumed the socket is ready
\r * to read data, and the method call routes the
\r * event to the various methods of InspSocket
\r * for you to handle. This can also cause the
\r * socket's state to change.
\r */
\r bool Poll();
\r\r /**
\r * This method returns the socket's file descriptor
\r * as assigned by the operating system, or -1
\r * if no descriptor has been assigned.
\r */
\r int GetFd();
\r\r /**
\r * This method causes the socket to close, and may
\r * also be triggered by other methods such as OnTimeout
\r * and OnError.
\r */
\r virtual void Close();
\r\r /**
\r * The destructor may implicitly call OnClose(), and
\r * will close() and shutdown() the file descriptor
\r * used for this socket.
\r */
\r virtual ~InspSocket();
\r\r /**
\r * This method attempts to connect to a hostname.
\r * This only occurs on a non-listening socket. This
\r * method is asyncronous.
\r */
\r virtual bool DoConnect();
\r\r /**
\r * This method marks the socket closed.
\r * The next time the core examines a socket marked
\r * as closed, the socket will be closed and the
\r * memory reclaimed.
\r *
\r * NOTE: This method is DEPRECIATED and will be
\r * ignored if called!
\r */
\r void MarkAsClosed();
\r\r /** Handle event from EventHandler parent class
\r */
\r void HandleEvent(EventType et, int errornum = 0);
\r\r /** Returns true if this socket is readable
\r */
\r bool Readable();
\r};
\r\r#endif
\r\r