Compare commits
2 Commits
f59049187e
...
efb49b8708
Author | SHA1 | Date | |
---|---|---|---|
efb49b8708 | |||
0aab173d94 |
|
@ -10,7 +10,7 @@ Connection::Connection(boost::asio::io_context & io)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Connection::writer_() -> void
|
auto Connection::writer_immediate() -> void
|
||||||
{
|
{
|
||||||
std::vector<boost::asio::const_buffer> buffers;
|
std::vector<boost::asio::const_buffer> buffers;
|
||||||
buffers.reserve(write_strings_.size());
|
buffers.reserve(write_strings_.size());
|
||||||
|
@ -45,14 +45,14 @@ auto Connection::writer() -> void
|
||||||
{
|
{
|
||||||
if (not self->write_strings_.empty())
|
if (not self->write_strings_.empty())
|
||||||
{
|
{
|
||||||
self->writer_();
|
self->writer_immediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
writer_();
|
writer_immediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ private:
|
||||||
EventDispatcher dispatcher_;
|
EventDispatcher dispatcher_;
|
||||||
|
|
||||||
auto writer() -> void;
|
auto writer() -> void;
|
||||||
auto writer_() -> void;
|
auto writer_immediate() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection(boost::asio::io_context & io);
|
Connection(boost::asio::io_context & io);
|
||||||
|
|
169
self_thread.cpp
169
self_thread.cpp
|
@ -1,9 +1,87 @@
|
||||||
#include "self_thread.hpp"
|
#include "self_thread.hpp"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
#include "connection.hpp"
|
#include "connection.hpp"
|
||||||
#include "ircmsg.hpp"
|
#include "ircmsg.hpp"
|
||||||
#include "irc_parse_thread.hpp"
|
#include "irc_parse_thread.hpp"
|
||||||
|
|
||||||
|
auto SelfThread::on_welcome(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
nickname_ = irc.args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_nick(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
if (is_my_mask(irc.source))
|
||||||
|
{
|
||||||
|
nickname_ = irc.args[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_umodeis(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
mode_ = irc.args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_join(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
if (is_my_mask(irc.source))
|
||||||
|
{
|
||||||
|
channels_.insert(std::string{irc.args[0]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_kick(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
if (is_my_nick(irc.args[1]))
|
||||||
|
{
|
||||||
|
channels_.erase(std::string{irc.args[0]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_part(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
if (is_my_mask(irc.source))
|
||||||
|
{
|
||||||
|
channels_.erase(std::string{irc.args[0]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::on_mode(IrcMsg const& irc) -> void
|
||||||
|
{
|
||||||
|
if (is_my_nick(irc.args[0]))
|
||||||
|
{
|
||||||
|
auto polarity = true;
|
||||||
|
for (char const c : irc.args[1])
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '+':
|
||||||
|
polarity = true;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
polarity = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (polarity)
|
||||||
|
{
|
||||||
|
mode_ += c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const ix = mode_.find(c);
|
||||||
|
if (ix != std::string::npos)
|
||||||
|
{
|
||||||
|
mode_.erase(ix, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||||
{
|
{
|
||||||
auto thread = std::make_shared<SelfThread>(connection);
|
auto thread = std::make_shared<SelfThread>(connection);
|
||||||
|
@ -14,64 +92,65 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||||
{
|
{
|
||||||
// Learn nickname from 001
|
// Learn nickname from 001
|
||||||
case IrcCommand::RPL_WELCOME:
|
case IrcCommand::RPL_WELCOME:
|
||||||
thread->nickname_ = event.irc.args[0];
|
thread->on_welcome(event.irc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Track changes to our nickname
|
// Track changes to our nickname
|
||||||
case IrcCommand::NICK:
|
case IrcCommand::NICK:
|
||||||
{
|
thread->on_nick(event.irc);
|
||||||
auto const bang = event.irc.source.find('!');
|
|
||||||
if (bang != std::string::npos
|
|
||||||
&& thread->nickname_ == event.irc.source.substr(0, bang)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
thread->nickname_ = event.irc.args[0];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// Re-establish user modes
|
// Re-establish user modes
|
||||||
case IrcCommand::RPL_UMODEIS:
|
case IrcCommand::RPL_UMODEIS:
|
||||||
thread->mode_ = event.irc.args[1];
|
thread->on_umodeis(event.irc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IrcCommand::JOIN:
|
||||||
|
thread->on_join(event.irc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IrcCommand::KICK:
|
||||||
|
thread->on_kick(event.irc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IrcCommand::PART:
|
||||||
|
thread->on_part(event.irc);
|
||||||
|
break;
|
||||||
|
|
||||||
// Interpret self mode changes
|
// Interpret self mode changes
|
||||||
case IrcCommand::MODE:
|
case IrcCommand::MODE:
|
||||||
if (2 == event.irc.args.size()
|
thread->on_mode(event.irc);
|
||||||
&& thread->nickname_ == event.irc.args[0]
|
break;
|
||||||
)
|
|
||||||
{
|
|
||||||
auto polarity = true;
|
|
||||||
for (char const c : event.irc.args[1])
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '+':
|
|
||||||
polarity = true;
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
polarity = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (polarity)
|
|
||||||
{
|
|
||||||
thread->mode_ += c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto const ix = thread->mode_.find(c);
|
|
||||||
if (ix != std::string::npos)
|
|
||||||
{
|
|
||||||
thread->mode_.erase(ix, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto SelfThread::get_my_nickname() const -> std::string const&
|
||||||
|
{
|
||||||
|
return nickname_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::get_my_mode() const -> std::string const&
|
||||||
|
{
|
||||||
|
return mode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::get_my_channels() const -> std::unordered_set<std::string> const&
|
||||||
|
{
|
||||||
|
return channels_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::is_my_nick(std::string_view nick) const -> bool
|
||||||
|
{
|
||||||
|
return nick == nickname_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SelfThread::is_my_mask(std::string_view mask) const -> bool
|
||||||
|
{
|
||||||
|
auto const bang = mask.find('!');
|
||||||
|
return bang != std::string_view::npos && nickname_ == mask.substr(0, bang);
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,39 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
struct Connection;
|
struct Connection;
|
||||||
|
struct IrcMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Thread to track this connection's identity, and IRC state.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class SelfThread
|
class SelfThread
|
||||||
{
|
{
|
||||||
Connection& connection_;
|
Connection& connection_;
|
||||||
std::string nickname_;
|
std::string nickname_;
|
||||||
std::string mode_;
|
std::string mode_;
|
||||||
|
std::unordered_set<std::string> channels_;
|
||||||
|
|
||||||
|
auto on_welcome(IrcMsg const& irc) -> void;
|
||||||
|
auto on_nick(IrcMsg const& irc) -> void;
|
||||||
|
auto on_umodeis(IrcMsg const& irc) -> void;
|
||||||
|
auto on_join(IrcMsg const& irc) -> void;
|
||||||
|
auto on_kick(IrcMsg const& irc) -> void;
|
||||||
|
auto on_part(IrcMsg const& irc) -> void;
|
||||||
|
auto on_mode(IrcMsg const& irc) -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SelfThread(Connection& connection) : connection_{connection} {}
|
SelfThread(Connection& connection) : connection_{connection} {}
|
||||||
static auto start(Connection&) -> std::shared_ptr<SelfThread>;
|
static auto start(Connection&) -> std::shared_ptr<SelfThread>;
|
||||||
|
|
||||||
|
auto get_my_nickname() const -> std::string const&;
|
||||||
|
auto get_my_mode() const -> std::string const&;
|
||||||
|
auto get_my_channels() const -> std::unordered_set<std::string> const&;
|
||||||
|
|
||||||
|
auto is_my_nick(std::string_view nick) const -> bool;
|
||||||
|
auto is_my_mask(std::string_view nick) const -> bool;
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct SnotePattern
|
||||||
std::regex regex;
|
std::regex regex;
|
||||||
};
|
};
|
||||||
|
|
||||||
SnotePattern const patterns[] =
|
SnotePattern static const patterns[] =
|
||||||
{
|
{
|
||||||
{SnoteTag::ClientConnecting,
|
{SnoteTag::ClientConnecting,
|
||||||
R"(^Client connecting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \{([^ ]*)\} <([^ ]*)> \[(.*)\]$)"},
|
R"(^Client connecting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \{([^ ]*)\} <([^ ]*)> \[(.*)\]$)"},
|
||||||
|
@ -79,7 +79,7 @@ SnotePattern const patterns[] =
|
||||||
"^\x02([^ ]+)\x02 set vhost ([^ ]+) on the \x02MARKED\x02 account ([^ ]+).$"},
|
"^\x02([^ ]+)\x02 set vhost ([^ ]+) on the \x02MARKED\x02 account ([^ ]+).$"},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto setup_database() -> hs_database_t*
|
static auto setup_database() -> hs_database_t*
|
||||||
{
|
{
|
||||||
auto const n = std::size(patterns);
|
auto const n = std::size(patterns);
|
||||||
std::vector<char const*> expressions;
|
std::vector<char const*> expressions;
|
||||||
|
|
|
@ -58,7 +58,10 @@ struct SnoteThread
|
||||||
auto operator()(hs_scratch * scratch) const -> void;
|
auto operator()(hs_scratch * scratch) const -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Database of server notice patterns
|
||||||
std::unique_ptr<hs_database, DbDeleter> db_;
|
std::unique_ptr<hs_database, DbDeleter> db_;
|
||||||
|
|
||||||
|
/// @brief HyperScan scratch space
|
||||||
std::unique_ptr<hs_scratch, ScratchDeleter> scratch_;
|
std::unique_ptr<hs_scratch, ScratchDeleter> scratch_;
|
||||||
|
|
||||||
static auto start(Connection& connection) -> std::shared_ptr<SnoteThread>;
|
static auto start(Connection& connection) -> std::shared_ptr<SnoteThread>;
|
||||||
|
|
|
@ -9,24 +9,22 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
WatchdogThread::WatchdogThread(Connection& connection)
|
WatchdogThread::WatchdogThread(Connection& connection)
|
||||||
: connection_{connection}
|
: connection_{connection}
|
||||||
, timer_{connection.get_executor()}
|
, timer_{connection.get_executor()}
|
||||||
, tried_ping{false}
|
, stalled_{false}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
auto WatchdogThread::on_activity() -> void
|
auto WatchdogThread::on_activity() -> void
|
||||||
{
|
{
|
||||||
tried_ping = false;
|
stalled_ = false;
|
||||||
timer_.expires_from_now(30s);
|
timer_.expires_from_now(WatchdogThread::TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto WatchdogThread::timeout_token()
|
auto WatchdogThread::start_timer()
|
||||||
{
|
{
|
||||||
return [weak = weak_from_this()](auto const& error)
|
timer_.async_wait([weak = weak_from_this()](auto const& error)
|
||||||
{
|
{
|
||||||
if (not error)
|
if (not error)
|
||||||
{
|
{
|
||||||
|
@ -35,28 +33,28 @@ auto WatchdogThread::timeout_token()
|
||||||
self->on_timeout();
|
self->on_timeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto WatchdogThread::on_timeout() -> void
|
auto WatchdogThread::on_timeout() -> void
|
||||||
{
|
{
|
||||||
if (tried_ping)
|
if (stalled_)
|
||||||
{
|
{
|
||||||
connection_.close();
|
connection_.close();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
send_ping(connection_, "watchdog");
|
send_ping(connection_, "watchdog");
|
||||||
tried_ping = true;
|
stalled_ = true;
|
||||||
timer_.expires_from_now(30s);
|
timer_.expires_from_now(WatchdogThread::TIMEOUT);
|
||||||
timer_.async_wait(timeout_token());
|
start_timer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto WatchdogThread::on_connect() -> void
|
auto WatchdogThread::on_connect() -> void
|
||||||
{
|
{
|
||||||
on_activity();
|
on_activity();
|
||||||
timer_.async_wait(timeout_token());
|
start_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto WatchdogThread::on_disconnect() -> void
|
auto WatchdogThread::on_disconnect() -> void
|
||||||
|
|
|
@ -2,20 +2,43 @@
|
||||||
|
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Connection;
|
class Connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Watch for connection activity and disconnect on stall
|
||||||
|
*
|
||||||
|
* The thread will send a ping if no message is received in the
|
||||||
|
* last TIMEOUT seconds. After another period of no messages
|
||||||
|
* the thread will disconnect the connection.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class WatchdogThread : std::enable_shared_from_this<WatchdogThread>
|
class WatchdogThread : std::enable_shared_from_this<WatchdogThread>
|
||||||
{
|
{
|
||||||
Connection& connection_;
|
Connection& connection_;
|
||||||
boost::asio::steady_timer timer_;
|
boost::asio::steady_timer timer_;
|
||||||
bool tried_ping;
|
|
||||||
|
|
||||||
|
/// @brief Set true and ping sent and false when reply received
|
||||||
|
bool stalled_;
|
||||||
|
|
||||||
|
const std::chrono::steady_clock::duration TIMEOUT = std::chrono::seconds{30};
|
||||||
|
|
||||||
|
/// @brief Start the timer
|
||||||
|
/// @return
|
||||||
|
auto start_timer();
|
||||||
|
|
||||||
|
/// @brief
|
||||||
auto on_activity() -> void;
|
auto on_activity() -> void;
|
||||||
auto timeout_token();
|
|
||||||
|
/// @brief
|
||||||
auto on_timeout() -> void;
|
auto on_timeout() -> void;
|
||||||
|
|
||||||
|
/// @brief callback for ConnectEvent event
|
||||||
auto on_connect() -> void;
|
auto on_connect() -> void;
|
||||||
|
|
||||||
|
/// @brief callback for DisconnectEvent event
|
||||||
auto on_disconnect() -> void;
|
auto on_disconnect() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user