* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- * E-mail:
- * <brain@chatspike.net>
- * <Craig@chatspike.net>
- *
- * Written by Craig Edwards, Craig McLure, and others.
+ * InspIRCd: (C) 2002-2008 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
-#ifndef __INSP_SOCKET_H__
-#define __INSP_SOCKET_H__
+#ifndef INSPIRCD_SOCKET_H
+#define INSPIRCD_SOCKET_H
+
+#ifndef WIN32
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <netinet/in.h>
-#include <sstream>
-#include <string>
-#include "dns.h"
-#include <deque>
-
-/**
- * States which a socket may be in
- */
-enum InspSocketState { I_DISCONNECTED, I_RESOLVING, I_CONNECTING, I_CONNECTED, I_LISTENING, I_ERROR };
-
-/**
- * Error types which a socket may exhibit
- */
-enum InspSocketError { I_ERR_TIMEOUT, I_ERR_SOCKET, I_ERR_CONNECT, I_ERR_BIND, I_ERR_RESOLVE, I_ERR_WRITE };
-
-/**
- * InspSocket is an extendable socket class which modules
- * can use for TCP socket support. It is fully integrated
- * into InspIRCds socket loop and attaches its sockets to
- * the core's instance of the SocketEngine class, meaning
- * that any sockets you create have the same power and
- * abilities as a socket created by the core itself.
- * To use InspSocket, you must inherit a class from it,
- * and use the InspSocket constructors to establish connections
- * and bindings.
- */
-class InspSocket
-{
-private:
-
- /**
- * The file descriptor of this socket
- */
- int fd;
-
- /**
- * The resolver for this socket
- */
- DNS dns;
-
- /**
- * The hostname connected to
- */
- std::string host;
-
- /**
- * The port connected to, or the port
- * this socket is listening on
- */
- int port;
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
- /**
- * The state for this socket, either
- * listening, connecting, connected
- * or error.
- */
- InspSocketState state;
-
- /**
- * The host being connected to,
- * in sockaddr form
- */
- sockaddr_in addr;
-
- /**
- * The host being connected to,
- * in in_addr form
- */
- in_addr addy;
+#else
- /**
- * When this time is reached,
- * the socket times out if it is
- * in the CONNECTING state
- */
- time_t timeout_end;
-
- /**
- * This value is true if the
- * socket has timed out.
- */
- bool timeout;
-
- /**
- * Socket input buffer, used by read(). The class which
- * extends InspSocket is expected to implement an extendable
- * buffer which can grow much larger than 64k,
- * this buffer is just designed to be temporary storage.
- * space.
- */
- char ibuf[65535];
-
- /**
- * The output buffer for this socket
- */
- std::deque<std::string> outbuffer;
-
- /**
- * The IP address being connected
- * to stored in string form for
- * easy retrieval by accessors.
- */
- std::string IP;
-
- /**
- * Client sockaddr structure used
- * by accept()
- */
- sockaddr_in client;
-
- /**
- * Server sockaddr structure used
- * by accept()
- */
- sockaddr_in server;
+#include "inspircd_win32wrapper.h"
- /**
- * Used by accept() to indicate the
- * sizes of the sockaddr_in structures
- */
- socklen_t length;
-
- /** Flushes the write buffer
- */
- bool FlushWriteBuffer();
-
- void SetQueues(int nfd);
-
-public:
-
- /**
- * The default constructor does nothing
- * and should not be used.
- */
- InspSocket();
-
- /**
- * This constructor is used to associate
- * an existing connecting with an InspSocket
- * class. The given file descriptor must be
- * valid, and when initialized, the InspSocket
- * will be set with the given IP address
- * and placed in CONNECTED state.
- */
- InspSocket(int newfd, char* ip);
-
- /**
- * This constructor is used to create a new
- * socket, either listening for connections, or an outbound connection to another host.
- * Note that if you specify a hostname in the 'host' parameter, then there will be an extra
- * step involved (a nonblocking DNS lookup) which will cause your connection to be established
- * slower than if it was an IP. Therefore, use an IP address where it is available instead.
- * @param host The hostname to connect to, or bind to
- * @param port The port number to connect to, or bind to
- * @param listening true to listen on the given host:port pair, or false to connect to them
- * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated
- */
- InspSocket(const std::string &host, int port, bool listening, unsigned long maxtime);
-
- /**
- * 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();
+#endif
- /**
- * 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
- */
- virtual void OnError(InspSocketError e);
+#include <cerrno>
+#include "socketengine.h"
- /**
- * When an established connection is terminated,
- * the OnDisconnect method is triggered.
- */
- virtual int OnDisconnect();
+/* Contains irc-specific definitions */
+namespace irc
+{
+ /** This namespace contains various protocol-independent helper classes.
+ * It also contains some types which are often used by the core and modules
+ * in place of inet_* functions and types.
+ */
+ namespace sockets
+ {
+
+ /* macros to the relevant system address description structs */
+#ifdef IPV6
+ /** insp_sockaddr for ipv6
+ */
+ typedef struct sockaddr_in6 insp_sockaddr;
+ /** insp_inaddr for ipv6
+ */
+ typedef struct in6_addr insp_inaddr;
+#define AF_FAMILY AF_INET6
+#define PF_PROTOCOL PF_INET6
+
+#else
+ /** insp_sockaddr for ipv4
+ */
+ typedef struct sockaddr_in insp_sockaddr;
+ /** insp_inaddr for ipv4
+ */
+ typedef struct in_addr insp_inaddr;
+#define AF_FAMILY AF_INET
+#define PF_PROTOCOL PF_INET
- /**
- * 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 InspSocket::Close() and deletes it.
- * @return false to close the socket
+#endif
+ /** Match raw binary data using CIDR rules.
+ *
+ * This function will use binary comparison to compare the
+ * two bit sequences, address and mask, up to mask_bits
+ * bits in size. If they match, it will return true.
+ * @param address The whole address, of 4 or 16 bytes in length
+ * @param mask The mask, from 1 to 16 bytes in length, anything
+ * from 1 to 128 bits of which is significant
+ * @param mask_Bits How many bits of the mask parameter are significant
+ * for this comparison.
+ * @returns True if the first mask_bits of address matches the first
+ * mask_bits of mask.
+ */
+ CoreExport bool MatchCIDRBits(const unsigned char* address, const unsigned char* mask, unsigned int mask_bits);
+
+ /** Match CIDR, without matching username/nickname parts.
+ *
+ * This function will compare a human-readable address against a human-
+ * readable CIDR mask, for example 1.2.3.4 against 1.2.0.0/16. This
+ * method supports both IPV4 and IPV6 addresses.
+ * @param address The human readable address, e.g. 1.2.3.4
+ * @param cidr_mask The human readable mask, e.g. 1.2.0.0/16
+ * @return True if the mask matches the address
+ */
+ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask);
+
+ /** Match CIDR, including an optional username/nickname part.
+ *
+ * This function will compare a human-readable address (plus
+ * optional username and nickname) against a human-readable
+ * CIDR mask, for example joe!bloggs\@1.2.3.4 against
+ * *!bloggs\@1.2.0.0/16. This method supports both IPV4 and
+ * IPV6 addresses.
+ * @param address The human readable address, e.g. fred\@1.2.3.4
+ * @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16
+ * @return True if the mask matches the address
+ */
+ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username);
+
+ /** Convert an insp_inaddr into human readable form.
+ *
+ * @param n An insp_inaddr (IP address) structure
+ * @return A human-readable address. IPV6 addresses
+ * will be shortened to remove fields which are 0.
+ */
+ CoreExport const char* insp_ntoa(insp_inaddr n);
+
+ /** Convert a human-readable address into an insp_inaddr.
+ *
+ * @param a A human-readable address
+ * @param n An insp_inaddr struct which the result
+ * will be copied into on success.
+ * @return This method will return a negative value if address
+ * does not contain a valid address family. 0 if the address is
+ * does not contain a valid string representing a valid network
+ * address. A positive value is returned if the network address
+ * was successfully converted.
+
+ * or any other number upon failure.
+ */
+ CoreExport int insp_aton(const char* a, insp_inaddr* n);
+
+ /** Create a new valid file descriptor using socket()
+ * @return On return this function will return a value >= 0 for success,
+ * or a negative value upon failure (negative values are invalid file
+ * descriptors)
+ */
+ CoreExport int OpenTCPSocket(const char* addr, int socktype = SOCK_STREAM);
+ }
+}
+
+
+
+/** This class handles incoming connections on client ports.
+ * It will create a new User for every valid connection
+ * and assign it a file descriptor.
+ */
+class CoreExport ListenSocketBase : public EventHandler
+{
+ protected:
+ /** The creator/owner of this object
*/
- virtual bool OnDataReady();
+ InspIRCd* ServerInstance;
+ /** Socket description (shown in stats p) */
+ std::string desc;
+ /** Socket address family */
+ int family;
+ /** Address socket is bound to */
+ std::string bind_addr;
+ /** Port socket is bound to */
+ int bind_port;
- /**
- * 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();
+ static sockaddr *sock_us;
- /**
- * Whenever close() is called, OnClose() will be
- * called first. Please note that this means
- * OnClose will be called alongside OnError(),
- * OnTimeout(), and Close(), and also when
- * cancelling a listening socket by calling
- * the destructor indirectly.
- */
- virtual void OnClose();
+ static sockaddr *client;
- /**
- * Reads all pending bytes from the socket
- * into a char* array which can be up to
- * 16 kilobytes in length.
- */
- virtual char* Read();
+ static sockaddr *raddr;
- /**
- * Returns the IP address associated with
- * this connection, or an empty string if
- * no IP address exists.
- */
- std::string GetIP();
+ static unsigned int socketcount;
- /**
- * This function checks if the socket has
- * timed out yet, given the current time
- * in the parameter.
- * @return true if timed out, false if not timed out
+ public:
+ /** Create a new listening socket
*/
- bool Timeout(time_t current);
-
- /**
- * Writes a std::string to the socket. No carriage
- * returns or linefeeds are appended to the string.
- * @param data The data to send
+ ListenSocketBase(InspIRCd* Instance, int port, const std::string &addr);
+ /** Handle an I/O event
*/
- virtual int Write(const std::string &data);
-
- /**
- * If your socket is a listening socket, when a new
- * connection comes in on the socket this method will
- * be called. Given the new file descriptor in the
- * parameters, and the IP, it is recommended you copy
- * them to a new instance of your socket class,
- * e.g.:
- *
- * MySocket* newsocket = new MySocket(newfd,ip);
- *
- * Once you have done this, you can then associate the
- * new socket with the core using Server::AddSocket().
+ void HandleEvent(EventType et, int errornum = 0);
+ /** Close the socket
*/
- virtual int OnIncomingConnection(int newfd, char* ip);
-
- /**
- * Changes the socket's state. The core uses this
- * to change socket states, and you should not call
- * it directly.
+ ~ListenSocketBase();
+ /** Set descriptive text
*/
- void SetState(InspSocketState s);
-
- /**
- * Returns the current socket state.
+ void SetDescription(const std::string &description)
+ {
+ desc = description;
+ }
+ /** Get description for socket
*/
- InspSocketState GetState();
-
- /**
- * Only the core should call this function.
- * When called, it is assumed the socket is ready
- * to read data, and the method call routes the
- * event to the various methods of InspSocket
- * for you to handle. This can also cause the
- * socket's state to change.
+ const std::string& GetDescription()
+ {
+ return desc;
+ }
+ /** Get port number for socket
*/
- bool Poll();
-
- /**
- * This method returns the socket's file descriptor
- * as assigned by the operating system, or -1
- * if no descriptor has been assigned.
+ int GetPort()
+ {
+ return bind_port;
+ }
+ /** Get IP address socket is bound to
*/
- int GetFd();
+ std::string &GetIP()
+ {
+ return bind_addr;
+ }
- /**
- * This method causes the socket to close, and may
- * also be triggered by other methods such as OnTimeout
- * and OnError.
+ /** Handles sockets internals crap of a connection, convenience wrapper really
*/
- virtual void Close();
+ void AcceptInternal();
- /**
- * The destructor may implicitly call OnClose(), and
- * will close() and shutdown() the file descriptor
- * used for this socket.
+ /** Called when a new connection has successfully been accepted on this listener.
+ * @param ipconnectedto The IP address the connection arrived on
+ * @param fd The file descriptor of the new connection
+ * @param incomingip The IP from which the connection was made
*/
- virtual ~InspSocket();
+ virtual void OnAcceptReady(const std::string &ipconnectedto, int fd, const std::string &incomingip) = 0;
+};
- virtual bool DoResolve();
- virtual bool DoConnect();
+class CoreExport ClientListenSocket : public ListenSocketBase
+{
+ virtual void OnAcceptReady(const std::string &ipconnectedto, int fd, const std::string &incomingip);
+ public:
+ ClientListenSocket(InspIRCd* Instance, int port, const std::string &addr) : ListenSocketBase(Instance, port, addr) { }
};
#endif
+