mirror of
git://git.acid.vegas/anope.git
synced 2024-11-30 11:36:41 +00:00
512 lines
12 KiB
C++
512 lines
12 KiB
C++
/*
|
|
*
|
|
* (C) 2003-2022 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 address family.
|
|
*/
|
|
int family() const;
|
|
|
|
/** 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;
|
|
|
|
/** Get the reverse address represented by this addr
|
|
* @return The reverse address
|
|
*/
|
|
Anope::string reverse() 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 destroy 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
|