/*
* InspIRCd -- Internet Relay Chat Daemon
*
- * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2013-2016 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2013-2014 Adam <Adam@anope.org>
+ * Copyright (C) 2012-2013, 2017-2020 Sadie Powell <sadie@witchery.services>
+ * Copyright (C) 2012 Robby <robby@chatbelgie.be>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
+ * Copyright (C) 2007-2008, 2017 Robin Burchell <robin+git@viroteck.net>
* Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2005-2008 Craig Edwards <brain@inspircd.org>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
#pragma once
-#include <vector>
#include <string>
-#include <map>
-#include "config.h"
#include "socket.h"
#include "base.h"
* EINPROGRESS. An event MAY be sent at any time that writes will not
* block.
*
- * Before calling HandleEvent, a socket engine MAY change the state of
+ * Before calling OnEventHandler*(), a socket engine MAY change the state of
* the FD back to FD_WANT_EDGE_WRITE if it is simpler (for example, if a
* one-shot notification was registered). If further writes are needed,
* it is the responsibility of the event handler to change the state to
*/
FD_WANT_EDGE_WRITE = 0x80,
/** Request a one-shot poll-style write notification. The socket will
- * return to the FD_WANT_NO_WRITE state before HandleEvent is called.
+ * return to the FD_WANT_NO_WRITE state before OnEventHandler*() is called.
*/
FD_WANT_SINGLE_WRITE = 0x100,
FD_WANT_WRITE_MASK = 0x1F0,
/** Add a trial read. During the next DispatchEvents invocation, this
- * will call HandleEvent with EVENT_READ unless reads are known to be
+ * will call OnEventHandlerRead() unless reads are known to be
* blocking.
*/
FD_ADD_TRIAL_READ = 0x1000,
/** Assert that reads are known to block. This cancels FD_ADD_TRIAL_READ.
- * Reset by SE before running EVENT_READ
+ * Reset by SE before running OnEventHandlerRead().
*/
FD_READ_WILL_BLOCK = 0x2000,
/** Add a trial write. During the next DispatchEvents invocation, this
- * will call HandleEvent with EVENT_WRITE unless writes are known to be
+ * will call OnEventHandlerWrite() unless writes are known to be
* blocking.
*
* This could be used to group several writes together into a single
*/
FD_ADD_TRIAL_WRITE = 0x4000,
/** Assert that writes are known to block. This cancels FD_ADD_TRIAL_WRITE.
- * Reset by SE before running EVENT_WRITE
+ * Reset by SE before running OnEventHandlerWrite().
*/
FD_WRITE_WILL_BLOCK = 0x8000,
/** This class is a basic I/O handler class.
* Any object which wishes to receive basic I/O events
* from the socketengine must derive from this class and
- * implement the HandleEvent() method. The derived class
+ * implement the OnEventHandler*() methods. The derived class
* must then be added to SocketEngine using the method
* SocketEngine::AddFd(), after which point the derived
- * class will receive events to its HandleEvent() method.
- * The derived class should also implement one of Readable()
- * and Writeable(). In the current implementation, only
- * Readable() is used. If this returns true, the socketengine
- * inserts a readable socket. If it is false, the socketengine
- * inserts a writeable socket. The derived class should never
- * change the value this function returns without first
- * deleting the socket from the socket engine. The only
+ * class will receive events to its OnEventHandler*() methods.
+ * The event mask passed to SocketEngine::AddFd() determines
+ * what events the EventHandler gets notified about and with
+ * what semantics. SocketEngine::ChangeEventMask() can be
+ * called to update the event mask later. The only
* requirement beyond this for an event handler is that it
* must have a file descriptor. What this file descriptor
* is actually attached to is completely up to you.
* registered with the SocketEngine
*/
int fd;
+
+ /** Swaps the internals of this EventHandler with another one.
+ * @param other A EventHandler to swap internals with.
+ */
+ void SwapInternals(EventHandler& other);
+
public:
/** Get the current file descriptor
* @return The file descriptor of this handler
*/
inline int GetFd() const { return fd; }
+ /** Checks if this event handler has a fd associated with it. */
+ inline bool HasFd() const { return fd >= 0; }
+
inline int GetEventMask() const { return event_mask; }
- /** Set a new file desciptor
+ /** Set a new file descriptor
* @param FD The new file descriptor. Do not call this method without
* first deleting the object from the SocketEngine if you have
* added it to a SocketEngine instance.
* its private members and internal behaviour
* should be treated as blackboxed, and vary
* from system to system and upon the config
- * settings chosen by the server admin. The current
- * version supports select, epoll and kqueue.
- * The configure script will enable a socket engine
- * based upon what OS is detected, and will derive
- * a class from SocketEngine based upon what it finds.
- * The derived classes file will also implement a
- * classfactory, SocketEngineFactory, which will
- * create a derived instance of SocketEngine using
- * polymorphism so that the core and modules do not
- * have to be aware of which SocketEngine derived
- * class they are using.
+ * settings chosen by the server admin.
*/
class CoreExport SocketEngine
{
*/
Statistics() : lastempty(0), TotalEvents(0), ReadEvents(0), WriteEvents(0), ErrorEvents(0) { }
- /** Increase the counters for bytes sent/received in this second.
- * @param len_in Bytes received, 0 if updating number of bytes written.
- * @param len_out Bytes sent, 0 if updating number of bytes read.
+ /** Update counters for network data received.
+ * This should be called after every read-type syscall.
+ * @param len_in Number of bytes received, or -1 for error, as typically
+ * returned by a read-style syscall.
*/
- void Update(size_t len_in, size_t len_out);
+ void UpdateReadCounters(int len_in);
+
+ /** Update counters for network data sent.
+ * This should be called after every write-type syscall.
+ * @param len_out Number of bytes sent, or -1 for error, as typically
+ * returned by a read-style syscall.
+ */
+ void UpdateWriteCounters(int len_out);
/** Get data transfer statistics.
- * @param kbitspersec_in Filled with incoming traffic in this second in kbit/s.
- * @param kbitspersec_out Filled with outgoing traffic in this second in kbit/s.
- * @param kbitspersec_total Filled with total traffic in this second in kbit/s.
+ * @param kbitpersec_in Filled with incoming traffic in this second in kbit/s.
+ * @param kbitpersec_out Filled with outgoing traffic in this second in kbit/s.
+ * @param kbitpersec_total Filled with total traffic in this second in kbit/s.
*/
void CoreExport GetBandwidth(float& kbitpersec_in, float& kbitpersec_out, float& kbitpersec_total) const;
**/
static std::vector<EventHandler*> ref;
- protected:
- /** Current number of descriptors in the engine
- */
+ /** Current number of descriptors in the engine. */
static size_t CurrentSetSize;
+
+ /** The maximum number of descriptors in the engine. */
+ static size_t MaxSetSize;
+
/** List of handlers that want a trial read/write
*/
static std::set<int> trials;
- static int MAX_DESCRIPTORS;
-
/** Socket engine statistics: count of various events, bandwidth usage
*/
static Statistics stats;
+ /** Look up the fd limit using rlimit. */
+ static void LookupMaxFds();
+
+ /** Terminates the program when the socket engine fails to initialize. */
+ static void InitError();
+
static void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
/** Add an event handler to the base socket engine. AddFd(EventHandler*, int) should call this.
static void ResizeDouble(std::vector<T>& vect)
{
if (SocketEngine::CurrentSetSize > vect.size())
- vect.resize(vect.size() * 2);
+ vect.resize(SocketEngine::CurrentSetSize * 2);
}
public:
/** 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().
+ * the required OnEventHandler*() methods.
* @param eh An event handling object to add
* @param event_mask The initial event mask for the object
*/
/** Returns the number of file descriptors reported by the system this program may use
* when it was started.
- * @return If positive, the number of file descriptors that the system reported that we
- * may use. Otherwise (<= 0) this number could not be determined.
+ * @return If non-zero the number of file descriptors that the system reported that we
+ * may use.
*/
- static int GetMaxFds() { return MAX_DESCRIPTORS; }
+ static size_t GetMaxFds() { return MaxSetSize; }
/** Returns the number of file descriptors being queried
* @return The set size
static bool HasFd(int fd);
/** Returns the EventHandler attached to a specific fd.
- * If the fd isnt in the socketengine, returns NULL.
+ * If the fd isn't in the socketengine, returns NULL.
* @param fd The event handler to look for
* @return A pointer to the event handler, or NULL
*/
* this doesn't wait long, only a couple of milliseconds. It returns the
* number of events which occurred during this call. This method will
* dispatch events to their handlers by calling their
- * EventHandler::HandleEvent() methods with the necessary EventType
- * value.
- * @return The number of events which have occured.
+ * EventHandler::OnEventHandler*() methods.
+ * @return The number of events which have occurred.
*/
static int DispatchEvents();
* @param buf The buffer in which the data that is sent is stored.
* @param len The size of the buffer.
* @param flags A flag value that controls the sending of the data.
- * @param to The remote IP address and port.
- * @param tolen The size of the to parameter.
+ * @param address The remote IP address and port.
* @return This method should return exactly the same values as the system call it emulates.
*/
- static int SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen);
+ static int SendTo(EventHandler* fd, const void* buf, size_t len, int flags, const irc::sockets::sockaddrs& address);
/** Abstraction for BSD sockets connect(2).
* This function should emulate its namesake system call exactly.
* @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
- * @param serv_addr The server IP address and port.
- * @param addrlen The size of the sockaddr parameter.
+ * @param address The server IP address and port.
* @return This method should return exactly the same values as the system call it emulates.
*/
- static int Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen);
+ static int Connect(EventHandler* fd, const irc::sockets::sockaddrs& address);
/** Make a file descriptor blocking.
* @param fd a file descriptor to set to blocking mode