Files
amnezia-client/client/core/tunnel.cpp
T

151 lines
4.1 KiB
C++

#include "tunnel.h"
#include <QTimer>
#include "daemon/interfaceconfig.h"
Tunnel::Tunnel(QString ifname,
amnezia::DockerContainer container,
QJsonObject config,
QString remoteAddress,
QObject* parent)
: QObject(parent),
m_ifname(std::move(ifname)),
m_remoteAddress(std::move(remoteAddress)),
m_container(container),
m_config(std::move(config)) {}
Tunnel::~Tunnel() = default;
void Tunnel::prepare() {
if (m_state != State::Idle) {
return;
}
setState(State::Preparing);
m_config.insert("ifname", m_ifname);
m_protocol.reset(VpnProtocol::factory(m_container, m_config));
if (!m_protocol) {
setState(State::Failed);
emit failed(amnezia::ErrorCode::InternalError);
return;
}
connect(m_protocol.data(), &VpnProtocol::connectionStateChanged,
this, &Tunnel::onProtocolStateChanged);
connect(m_protocol.data(), &VpnProtocol::bytesChanged,
this, &Tunnel::bytesChanged);
connect(m_protocol.data(), &VpnProtocol::tunnelAddressesUpdated,
this, &Tunnel::addressesUpdated);
connect(m_protocol.data(), &VpnProtocol::primaryReady,
this, &Tunnel::onPrimaryReady);
connect(m_protocol.data(), &VpnProtocol::primaryFailed,
this, &Tunnel::onPrimaryFailed);
startActivationDeadline(ACTIVATION_TIMEOUT_MSEC);
const amnezia::ErrorCode err = m_protocol->start();
if (err != amnezia::ErrorCode::NoError) {
cancelActivationDeadline();
setState(State::Failed);
emit failed(err);
}
}
void Tunnel::commit() {
if (m_state != State::Prepared) {
return;
}
setState(State::Committing);
startActivationDeadline(ACTIVATION_TIMEOUT_MSEC);
if (m_protocol) {
m_protocol->setPrimary(m_config);
}
}
void Tunnel::onPrimaryReady() {
if (m_state != State::Committing) {
return;
}
cancelActivationDeadline();
setState(State::Active);
emit activated();
}
void Tunnel::onPrimaryFailed() {
if (m_state != State::Committing) {
return;
}
cancelActivationDeadline();
setState(State::Failed);
emit failed(m_protocol ? m_protocol->lastError() : amnezia::ErrorCode::InternalError);
}
void Tunnel::deactivate() {
if (m_state == State::Gone || m_state == State::Idle) {
return;
}
cancelActivationDeadline();
setState(State::Gone);
if (m_protocol) {
m_protocol->stop();
}
}
void Tunnel::restart() {
deactivate();
setState(State::Idle);
prepare();
}
void Tunnel::setState(State next) {
if (m_state == next) {
return;
}
m_state = next;
emit stateChanged(m_state);
}
void Tunnel::startActivationDeadline(int msec) {
if (!m_deadline) {
m_deadline = new QTimer(this);
m_deadline->setSingleShot(true);
connect(m_deadline, &QTimer::timeout, this, [this]() {
if (m_state != State::Preparing && m_state != State::Committing) {
return;
}
setState(State::Failed);
emit failed(amnezia::ErrorCode::InternalError);
});
}
m_deadline->start(msec);
}
void Tunnel::cancelActivationDeadline() {
if (m_deadline) {
m_deadline->stop();
}
}
void Tunnel::onProtocolStateChanged(Vpn::ConnectionState state) {
if (m_state == State::Preparing && state == Vpn::ConnectionState::Connected) {
cancelActivationDeadline();
setState(State::Prepared);
emit prepared();
return;
}
const bool inLiveState = m_state == State::Preparing
|| m_state == State::Prepared
|| m_state == State::Committing
|| m_state == State::Active;
const bool isFailureSignal = state == Vpn::ConnectionState::Disconnected
|| state == Vpn::ConnectionState::Error;
if (inLiveState && isFailureSignal) {
cancelActivationDeadline();
setState(State::Failed);
emit failed(m_protocol ? m_protocol->lastError() : amnezia::ErrorCode::InternalError);
}
}