1
0
mirror of https://github.com/anope/anope.git synced 2026-06-23 20:46:38 +02:00
Files
anope/include/sockets.h
T
Adam 866f3f32ab Speed up akill xline checks
Cache xline nick, user, host, etc instead of rebuilding it everytime its
requested. Store users ip in sockaddr form and not string form to
prevent having to rebuild sockaddrs when checking xlines.

Also do not try to convert empty config values in Config::Get as this
can be rather common if a non string configuration value is not set, and
the cost of the ConvertException is great.
2014-05-20 21:16:00 -04:00

504 lines
12 KiB
C++

/*
*
* (C) 2003-2014 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
*/
#ifndef SOCKETS_H
#define SOCKETS_H
#ifndef _WIN32
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include "anope.h"
#define NET_BUFSIZE 65535
/** A sockaddr union used to combine IPv4 and IPv6 sockaddrs
*/
union CoreExport sockaddrs
{
sockaddr sa;
sockaddr_in sa4;
sockaddr_in6 sa6;
/** Construct the object, sets everything to 0
*/
sockaddrs(const Anope::string &address = "");
/** Memset the object to 0
*/
void clear();
/** Get the size of the sockaddr we represent
* @return The size
*/
size_t size() const;
/** Get the port represented by this addr
* @return The port, or -1 on fail
*/
int port() const;
/** Get the address represented by this addr
* @return The address
*/
Anope::string addr() const;
/* Is this address ipv6? */
bool ipv6() const;
/** Check if this sockaddr has data in it
*/
bool valid() const;
/** Compares with sockaddr with another. Compares address type, port, and address
* @return true if they are the same
*/
bool operator==(const sockaddrs &other) const;
/* The same as above but not */
inline bool operator!=(const sockaddrs &other) const { return !(*this == other); }
/** The equivalent of inet_pton
* @param type AF_INET or AF_INET6
* @param address The address to place in the sockaddr structures
* @param pport An option port to include in the sockaddr structures
* @throws A socket exception if given invalid IPs
*/
void pton(int type, const Anope::string &address, int pport = 0);
/** The equivalent of inet_ntop
* @param type AF_INET or AF_INET6
* @param address The in_addr or in_addr6 structure
* @throws A socket exception if given an invalid structure
*/
void ntop(int type, const void *src);
};
class CoreExport cidr
{
sockaddrs addr;
Anope::string cidr_ip;
unsigned short cidr_len;
public:
cidr(const Anope::string &ip);
cidr(const Anope::string &ip, unsigned char len);
cidr(const sockaddrs &ip, unsigned char len);
Anope::string mask() const;
bool match(const sockaddrs &other);
bool valid() const;
bool operator<(const cidr &other) const;
bool operator==(const cidr &other) const;
bool operator!=(const cidr &other) const;
struct CoreExport hash
{
size_t operator()(const cidr &s) const;
};
};
class SocketException : public CoreException
{
public:
/** Constructor for socket exceptions
* @param message Error message
*/
SocketException(const Anope::string &message) : CoreException(message) { }
/** Destructor
* @throws Nothing
*/
virtual ~SocketException() throw() { }
};
enum SocketFlag
{
SF_DEAD = 1,
SF_READABLE,
SF_WRITABLE,
SF_CONNECTING,
SF_CONNECTED,
SF_ACCEPTING,
SF_ACCEPTED,
SF_SIZE
};
class CoreExport SocketIO
{
public:
virtual ~SocketIO() { }
/** Receive something from the buffer
* @param s The socket
* @param buf The buf to read to
* @param sz How much to read
* @return Number of bytes received
*/
virtual int Recv(Socket *s, char *buf, size_t sz);
/** Write something to the socket
* @param s The socket
* @param buf The data to write
* @param size The length of the data
*/
virtual int Send(Socket *s, const char *buf, size_t sz);
int Send(Socket *s, const Anope::string &buf);
/** Accept a connection from a socket
* @param s The socket
* @return The new socket
*/
virtual ClientSocket *Accept(ListenSocket *s);
/** Finished accepting a connection from a socket
* @param s The socket
* @return SF_ACCEPTED if accepted, SF_ACCEPTING if still in process, SF_DEAD on error
*/
virtual SocketFlag FinishAccept(ClientSocket *cs);
/** Bind a socket
* @param s The socket
* @param ip The IP to bind to
* @param port The optional port to bind to
*/
virtual void Bind(Socket *s, const Anope::string &ip, int port = 0);
/** Connect the socket
* @param s The socket
* @param target IP to connect to
* @param port to connect to
*/
virtual void Connect(ConnectionSocket *s, const Anope::string &target, int port);
/** Called to potentially finish a pending connection
* @param s The socket
* @return SF_CONNECTED on success, SF_CONNECTING if still pending, and SF_DEAD on error.
*/
virtual SocketFlag FinishConnect(ConnectionSocket *s);
/** Called when the socket is destructing
*/
virtual void Destroy() { }
};
class CoreExport Socket
{
protected:
/* Socket FD */
int sock;
/* Is this an IPv6 socket? */
bool ipv6;
public:
std::bitset<SF_SIZE> flags;
/* Sockaddrs for bind() (if it's bound) */
sockaddrs bindaddr;
/* I/O functions used for this socket */
SocketIO *io;
/** Empty constructor, should not be called.
*/
Socket();
/** Constructor, possibly creates the socket and adds it to the engine
* @param sock The socket to use, -1 if we need to create our own
* @param ipv6 true if using ipv6
* @param type The socket type, defaults to SOCK_STREAM
*/
Socket(int sock, bool ipv6 = false, int type = SOCK_STREAM);
/** Destructor, closes the socket and removes it from the engine
*/
virtual ~Socket();
/** Get the socket FD for this socket
* @return the fd
*/
int GetFD() const;
/** Check if this socket is IPv6
* @return true or false
*/
bool IsIPv6() const;
/** Mark a socket as (non)blocking
* @param state true to enable blocking, false to disable blocking
* @return true if the socket is now blocking
*/
bool SetBlocking(bool state);
/** Bind the socket to an ip and port
* @param ip The ip
* @param port The port
*/
void Bind(const Anope::string &ip, int port = 0);
/** Called when there either is a read or write event.
* @return true to continue to call ProcessRead/ProcessWrite, false to not continue
*/
virtual bool Process();
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
virtual bool ProcessRead();
/** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
virtual bool ProcessWrite();
/** Called when there is an error for this socket
* @return true on success, false to drop this socket
*/
virtual void ProcessError();
};
class CoreExport BufferedSocket : public virtual Socket
{
protected:
/* Things read from the socket */
Anope::string read_buffer;
/* Things to be written to the socket */
Anope::string write_buffer;
/* How much data was received from this socket on this recv() */
int recv_len;
public:
BufferedSocket();
virtual ~BufferedSocket();
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
bool ProcessRead() anope_override;
/** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
bool ProcessWrite() anope_override;
/** Gets the new line from the input buffer, if any
*/
const Anope::string GetLine();
/** Write to the socket
* @param message The message
*/
protected:
virtual void Write(const char *buffer, size_t l);
public:
void Write(const char *message, ...);
void Write(const Anope::string &message);
/** Get the length of the read buffer
* @return The length of the read buffer
*/
int ReadBufferLen() const;
/** Get the length of the write buffer
* @return The length of the write buffer
*/
int WriteBufferLen() const;
};
class CoreExport BinarySocket : public virtual Socket
{
protected:
struct DataBlock
{
char *orig;
char *buf;
size_t len;
DataBlock(const char *b, size_t l);
~DataBlock();
};
/* Data to be written out */
std::deque<DataBlock *> write_buffer;
public:
BinarySocket();
virtual ~BinarySocket();
/** Called when there is something to be received for this socket
* @return true on success, false to drop this socket
*/
bool ProcessRead() anope_override;
/** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
bool ProcessWrite() anope_override;
/** Write data to the socket
* @param buffer The data to write
* @param l The length of the data; if 0 then this function returns without doing anything
*/
virtual void Write(const char *buffer, size_t l);
void Write(const char *message, ...);
void Write(const Anope::string &message);
/** Called with data from the socket
* @param buffer The data
* @param l The length of buffer
* @return true to continue reading, false to drop the socket
*/
virtual bool Read(const char *buffer, size_t l);
};
class CoreExport ListenSocket : public virtual Socket
{
public:
/** Constructor
* @param bindip The IP to bind to
* @param port The port to listen on
* @param ipv6 true for ipv6
*/
ListenSocket(const Anope::string &bindip, int port, bool ipv6);
virtual ~ListenSocket();
/** Process what has come in from the connection
* @return false to destory this socket
*/
bool ProcessRead();
/** Called when a connection is accepted
* @param fd The FD for the new connection
* @param addr The sockaddr for where the connection came from
* @return The new socket
*/
virtual ClientSocket *OnAccept(int fd, const sockaddrs &addr) = 0;
};
class CoreExport ConnectionSocket : public virtual Socket
{
public:
/* Sockaddrs for connection ip/port */
sockaddrs conaddr;
/** Connect the socket
* @param TargetHost The target host to connect to
* @param Port The target port to connect to
*/
void Connect(const Anope::string &TargetHost, int Port);
/** Called when there either is a read or write event.
* Used to determine whether or not this socket is connected yet.
* @return true to continue to call ProcessRead/ProcessWrite, false to not continue
*/
bool Process() anope_override;
/** Called when there is an error for this socket
* @return true on success, false to drop this socket
*/
void ProcessError() anope_override;
/** Called on a successful connect
*/
virtual void OnConnect();
/** Called when a connection is not successful
* @param error The error
*/
virtual void OnError(const Anope::string &error);
};
class CoreExport ClientSocket : public virtual Socket
{
public:
/* Listen socket this connection came from */
ListenSocket *ls;
/* Clients address */
sockaddrs clientaddr;
/** Constructor
* @param ls Listen socket this connection is from
* @param addr Address the connection came from
*/
ClientSocket(ListenSocket *ls, const sockaddrs &addr);
/** Called when there either is a read or write event.
* Used to determine whether or not this socket is connected yet.
* @return true to continue to call ProcessRead/ProcessWrite, false to not continue
*/
bool Process() anope_override;
/** Called when there is an error for this socket
* @return true on success, false to drop this socket
*/
void ProcessError() anope_override;
/** Called when a client has been accepted() successfully.
*/
virtual void OnAccept();
/** Called when there was an error accepting the client
*/
virtual void OnError(const Anope::string &error);
};
class CoreExport Pipe : public Socket
{
public:
/** The FD of the write pipe
* this->sock is the readfd
*/
int write_pipe;
Pipe();
~Pipe();
/** Called when data is to be read, reads the data then calls OnNotify
*/
bool ProcessRead() anope_override;
/** Write data to this pipe
* @param data The data to write
* @param sz The amount of data to wirite
*/
void Write(const char *data, size_t sz);
inline void Write(const Anope::string &data) { this->Write(data.c_str(), data.length() + 1); }
/** Read data from this pipe
* @param data A buffer to read data into
* @param sz The size of the buffer
* @return The amount of data read
*/
int Read(char *data, size_t sz);
/** Mark the write end of this pipe (non)blocking
* @param state true to enable blocking, false to disable blocking
* @return true if the socket is now blocking
*/
bool SetWriteBlocking(bool state);
/** Called when this pipe needs to be woken up
* Is the same as Write("\0", 1)
*/
void Notify();
/** Called after ProcessRead comes back from Notify(), overload to do something useful
*/
virtual void OnNotify() = 0;
};
extern CoreExport uint32_t TotalRead;
extern CoreExport uint32_t TotalWritten;
extern CoreExport SocketIO NormalSocketIO;
#endif // SOCKET_H