Skip to content

Commit

Permalink
Use RAII for loop registration
Browse files Browse the repository at this point in the history
There's probably a number of situations where registrations
with the loop are left behind and cause issues.  Instead, use
RAII to avoid this.
  • Loading branch information
chrisstaite committed Jan 13, 2025
1 parent dcd2d53 commit 317f41d
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 108 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ set(CommonSources
include/verify_cache.h
src/verify_cache.cpp
include/i_loop.h
src/i_loop.cpp
include/loop.h
src/loop.cpp
include/server.h
Expand Down
10 changes: 7 additions & 3 deletions include/forwarder_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "config_parser.h"
#include "i_loop.h"
#include "openssl/ssl_connection.h"

#include <memory>
Expand All @@ -12,7 +13,6 @@

namespace dote {

class ILoop;
class IForwarderConfig;
class Socket;

Expand Down Expand Up @@ -93,8 +93,6 @@ class ForwarderConnection
void configureVerifier();

/// \brief Perform the initial connection
///
/// \param handle The socket that is available to connect on
void connect(int handle);

/// \brief Nicely shutdown the connection
Expand Down Expand Up @@ -136,6 +134,12 @@ class ForwarderConnection
State m_state;
/// The established connection to the forwarder
std::shared_ptr<Socket> m_socket;
/// The current read registration for m_socket.
ILoop::Registration m_read;
/// The current write registration for m_socket.
ILoop::Registration m_write;
/// The current exception registration for m_socket.
ILoop::Registration m_exception;
/// The write buffer, the request will be a single message
std::vector<char> m_buffer;
/// The chosen forwarder that this is connected to
Expand Down
73 changes: 70 additions & 3 deletions include/i_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,72 @@ class ILoop
public:
virtual ~ILoop() = default;

/// \brief A registration type.
enum Type {
/// A special value to avoid deregistering on move.
Moved,
/// A read registration.
Read,
/// A write registration.
Write,
/// An exception registration.
Exception,
};

/// \brief This class is created with a read, write or exception
/// registration and automatically removes the registration
/// on destruction.
///
/// NOTE: This object must not outlive the Loop that created it.
class Registration
{
public:
Registration(const Registration&) = delete;
Registration& operator=(const Registration&) = delete;

/// \brief Construct an invalid Registration.
Registration();

/// \brief Create a registration for a given loop.
///
/// \param loop The loop that this registration is for.
/// \param handle The handle of the registration
/// \param type The type of the registration.
Registration(ILoop* loop, int handle, Type type);

/// \brief Take ownership of a registration.
///
/// \param other The instance to take ownership from.
Registration(Registration&& other);

/// \brief Take ownership of a registration.
///
/// \param other The instance to take ownership from.
Registration& operator=(Registration&& other);

/// \brief Deregister from the loop.
~Registration();

operator bool() const { return valid(); }

/// \brief Whether the registration is valid (i.e. the execution was
// successful).
bool valid() const;

/// \brief Clear the registration.
void reset();

private:
friend class ILoop;

/// The loop that this registration is for.
ILoop* m_loop;
/// The handle to deregister.
int m_handle;
/// The type of registration.
Type m_type;
};

/// The type to call when the loop is available, called with the
/// handle that caused it to be called
using Callback = std::function<void(int)>;
Expand All @@ -23,7 +89,7 @@ class ILoop
/// \param timeout The time at which to call exception on the handle
///
/// \return True if the handle is not already registered and now is
virtual bool registerRead(int handle, Callback callback, time_t timeout) = 0;
virtual Registration registerRead(int handle, Callback callback, time_t timeout) = 0;

/// \brief Register for write availability on a given handle
///
Expand All @@ -32,16 +98,17 @@ class ILoop
/// \param timeout The time at which to call exception on the handle
///
/// \return True if the handle is not already registered and now is
virtual bool registerWrite(int handle, Callback callback, time_t timeout) = 0;
virtual Registration registerWrite(int handle, Callback callback, time_t timeout) = 0;

/// \brief Register for exceptions on a given handle
///
/// \param handle The handle to register for exceptions
/// \param callback The callback to call if it triggers
///
/// \return True if the handle is not already registered and now is
virtual bool registerException(int handle, Callback callback) = 0;
virtual Registration registerException(int handle, Callback callback) = 0;

protected:
/// \brief Remove a read handle from the loop
///
/// \param handle The handle to remove read handles for
Expand Down
8 changes: 8 additions & 0 deletions include/ip_lookup.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

#pragma once

#include "i_loop.h"

#include <memory>

namespace dote {
Expand Down Expand Up @@ -50,6 +52,12 @@ class IpLookup
std::shared_ptr<Loop> m_loop;
/// The socket that the connection if performed on
std::shared_ptr<Socket> m_socket;
/// The current read registration for m_socket.
ILoop::Registration m_read;
/// The current write registration for m_socket.
ILoop::Registration m_write;
/// The current exception registration for m_socket.
ILoop::Registration m_exception;
/// The connection that was made to the IP address
std::shared_ptr<openssl::ISslConnection> m_connection;
/// The time at which the lookup will be considered failed
Expand Down
14 changes: 7 additions & 7 deletions include/loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,27 @@ class Loop : public ILoop
/// \param callback The callback to call if it triggers
/// \param timeout The time at which to call exception on the handle
///
/// \return True if the handle is not already registered and now is
bool registerRead(int handle, Callback callback, time_t timeout) override;
/// \return A registration which is valid on success
Registration registerRead(int handle, Callback callback, time_t timeout) override;

/// \brief Register for write availability on a given handle
///
/// \param handle The handle to register for writing
/// \param callback The callback to call if it triggers
/// \param timeout The time at which to call exception on the handle
///
/// \return True if the handle is not already registered and now is
bool registerWrite(int handle, Callback callback, time_t timeout) override;
/// \return A registration which is valid on success
Registration registerWrite(int handle, Callback callback, time_t timeout) override;

/// \brief Register for exceptions on a given handle
///
/// \param handle The handle to register for exceptions
/// \param callback The callback to call if it triggers
///
/// \return True if the handle is not already registered and now is
bool registerException(int handle, Callback callback) override;
/// \return A registration which is valid on success
Registration registerException(int handle, Callback callback) override;

private:
/// \brief Remove a read handle from the loop
///
/// \param handle The handle to remove read handles for
Expand All @@ -67,7 +68,6 @@ class Loop : public ILoop
/// \param handle The handle to remove exception handles for
void removeException(int handle) override;

private:
/// \brief Call a callback in a set of functions
///
/// \param functions The functions to lookup the callback in
Expand Down
7 changes: 4 additions & 3 deletions include/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
#pragma once

#include "config_parser.h"
#include "i_loop.h"

#include <vector>
#include <memory>

namespace dote {

class ILoop;
class Socket;
class IForwarders;

Expand Down Expand Up @@ -46,8 +46,9 @@ class Server
std::shared_ptr<ILoop> m_loop;
/// The available forwarders
std::shared_ptr<IForwarders> m_forwarders;
/// The sockets that we are recieving from
std::vector<std::shared_ptr<Socket>> m_serverSockets;
using SocketAndRegistration = std::pair<std::shared_ptr<Socket>, ILoop::Registration>;
/// The sockets that we are recieving from and their read registrations.
std::vector<SocketAndRegistration> m_serverSockets;
};

} // namespace dote
3 changes: 3 additions & 0 deletions include/vyatta_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "config_parser.h"
#include "i_loop.h"

namespace dote {

Expand Down Expand Up @@ -41,6 +42,8 @@ class VyattaCheck

/// A handle to the inotify watch on the configuration file
int m_fd;
/// The read registration for m_fd.
ILoop::Registration m_read;
/// The main DoTe instance to configure on configuration changes
Dote* m_dote;
/// The base configuration to augment
Expand Down
2 changes: 1 addition & 1 deletion src/forwarder_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ std::vector<ConfigParser::Forwarder>::const_iterator ForwarderConfig::end() cons
return m_forwarders.cend();
}

void ForwarderConfig::setBad(const ConfigParser::Forwarder &config)
void ForwarderConfig::setBad(const ConfigParser::Forwarder& config)
{
// Look for the config in the forwarder list and move it to the end
for (auto it = m_forwarders.begin(); it != m_forwarders.end(); ++it)
Expand Down
Loading

0 comments on commit 317f41d

Please sign in to comment.