separated managers functions and improved error messages
This commit is contained in:
parent
e8a6a0a400
commit
dfb96a7853
13 changed files with 413 additions and 261 deletions
|
@ -11,8 +11,8 @@ add_executable(M2-PT-DRP
|
||||||
source/packets/audio/AudioPacketData.hpp
|
source/packets/audio/AudioPacketData.hpp
|
||||||
source/utils/audio/audio.cpp
|
source/utils/audio/audio.cpp
|
||||||
source/utils/audio/audio.hpp
|
source/utils/audio/audio.hpp
|
||||||
source/Manager.cpp
|
source/managers/Manager.cpp
|
||||||
source/Manager.hpp
|
source/managers/Manager.hpp
|
||||||
source/packets/base/Packet.hpp
|
source/packets/base/Packet.hpp
|
||||||
source/behavior/events/types.hpp
|
source/behavior/events/types.hpp
|
||||||
source/packets/base/Packet.cpp
|
source/packets/base/Packet.cpp
|
||||||
|
@ -66,6 +66,10 @@ add_executable(M2-PT-DRP
|
||||||
source/packets/audio/AudioPacketData.cpp
|
source/packets/audio/AudioPacketData.cpp
|
||||||
source/packets/info/InfoPacketData.cpp
|
source/packets/info/InfoPacketData.cpp
|
||||||
source/packets/search/SearchPacketData.cpp
|
source/packets/search/SearchPacketData.cpp
|
||||||
|
source/managers/SendManager.cpp
|
||||||
|
source/managers/ReceiveManager.cpp
|
||||||
|
source/managers/ReceiveManager.hpp
|
||||||
|
source/managers/SendManager.hpp
|
||||||
)
|
)
|
||||||
target_include_directories(M2-PT-DRP PRIVATE
|
target_include_directories(M2-PT-DRP PRIVATE
|
||||||
source
|
source
|
||||||
|
|
|
@ -3,15 +3,20 @@
|
||||||
#include "utils/crypto/rsa/RsaKeyPair.hpp"
|
#include "utils/crypto/rsa/RsaKeyPair.hpp"
|
||||||
|
|
||||||
|
|
||||||
Context::Context() {
|
Context::Context(const int socket, addrinfo* broadcastAddressInfo) {
|
||||||
const auto keyPair = drp::util::crypto::RsaKeyPair(2048);
|
const auto keyPair = drp::util::crypto::RsaKeyPair(2048);
|
||||||
|
|
||||||
this->me = Peer(keyPair.getPublicKey());
|
// communication
|
||||||
this->cryptoRsaPrivateKey = keyPair.getPrivateKey();
|
this->socket = socket;
|
||||||
|
this->broadcastAddressInfo = broadcastAddressInfo;
|
||||||
this->socket = -1;
|
|
||||||
this->broadcastAddressInfo = nullptr;
|
|
||||||
this->server = nullptr;
|
this->server = nullptr;
|
||||||
|
|
||||||
|
// ourselves
|
||||||
|
this->me = Peer(keyPair.getPublicKey());
|
||||||
|
|
||||||
|
// others
|
||||||
this->latestPeerDiscovery = std::chrono::high_resolution_clock::now();
|
this->latestPeerDiscovery = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// crytography
|
||||||
|
this->cryptoRsaPrivateKey = keyPair.getPrivateKey();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,21 @@
|
||||||
*/
|
*/
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
explicit Context();
|
explicit Context(int socket, addrinfo* broadcastAddressInfo);
|
||||||
|
|
||||||
|
// communication
|
||||||
int socket; /// current socket file descriptor, used to communicate
|
int socket; /// current socket file descriptor, used to communicate
|
||||||
addrinfo* broadcastAddressInfo; /// address used to broadcast messages
|
addrinfo* broadcastAddressInfo; /// address used to broadcast messages
|
||||||
std::shared_ptr<RemotePeer> server; /// peer currently used as the server
|
std::shared_ptr<RemotePeer> server; /// peer currently used as the server
|
||||||
|
|
||||||
|
// ourselves
|
||||||
Peer me; /// information about our own machine
|
Peer me; /// information about our own machine
|
||||||
|
|
||||||
|
// others
|
||||||
std::list<std::shared_ptr<RemotePeer>> remotePeers {}; /// information about other machines
|
std::list<std::shared_ptr<RemotePeer>> remotePeers {}; /// information about other machines
|
||||||
std::chrono::high_resolution_clock::time_point latestPeerDiscovery; /// time of the latest discovered machine
|
std::chrono::high_resolution_clock::time_point latestPeerDiscovery; /// time of the latest discovered machine
|
||||||
|
|
||||||
|
// cryptography
|
||||||
drp::util::crypto::RsaPrivateKey cryptoRsaPrivateKey {}; /// the RSA private key
|
drp::util::crypto::RsaPrivateKey cryptoRsaPrivateKey {}; /// the RSA private key
|
||||||
drp::util::crypto::AesKey256 cryptoAesKey = {}; /// the AES secret key
|
drp::util::crypto::AesKey256 cryptoAesKey = {}; /// the AES secret key
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,210 +0,0 @@
|
||||||
#include "Manager.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <ostream>
|
|
||||||
#include <thread>
|
|
||||||
#include <random>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include "behavior/events/types.hpp"
|
|
||||||
#include "behavior/events/audio/AudioEvent.hpp"
|
|
||||||
#include "behavior/events/info/InfoEvent.hpp"
|
|
||||||
#include "behavior/events/pong/PongEvent.hpp"
|
|
||||||
#include "behavior/events/search/SearchEvent.hpp"
|
|
||||||
#include "packets/base/Packet.hpp"
|
|
||||||
#include "behavior/tasks/client/ClientTask.hpp"
|
|
||||||
#include "behavior/tasks/server/ServerTask.hpp"
|
|
||||||
#include "behavior/tasks/undefined/UndefinedTask.hpp"
|
|
||||||
#include "utils/crypto/aes/AesKey.hpp"
|
|
||||||
#include "utils/crypto/rsa/RsaKeyPair.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
Manager::Manager(const std::string& address, const std::string& port, const bool useIpv6) {
|
|
||||||
std::cout << "Broadcast address: " << address << ":" << port << " (" << (useIpv6 ? "IPv6" : "IPv4") << ")" << std::endl;
|
|
||||||
|
|
||||||
this->context = std::make_shared<Context>();
|
|
||||||
|
|
||||||
// register the different events type
|
|
||||||
this->eventRegistry = {
|
|
||||||
{drp::event::EventType::PONG, std::make_shared<drp::event::PongEvent>()},
|
|
||||||
{drp::event::EventType::SEARCH, std::make_shared<drp::event::SearchEvent>()},
|
|
||||||
{drp::event::EventType::INFO, std::make_shared<drp::event::InfoEvent>()},
|
|
||||||
{drp::event::EventType::AUDIO, std::make_shared<drp::event::AudioEvent>()},
|
|
||||||
};
|
|
||||||
|
|
||||||
// register the different tasks type
|
|
||||||
this->taskRegistry = {
|
|
||||||
{drp::task::TaskType::UNDEFINED, std::make_shared<drp::task::UndefinedTask>()},
|
|
||||||
{drp::task::TaskType::CLIENT, std::make_shared<drp::task::ClientTask>()},
|
|
||||||
{drp::task::TaskType::SERVER, std::make_shared<drp::task::ServerTask>()},
|
|
||||||
};
|
|
||||||
|
|
||||||
// hints for the communication
|
|
||||||
addrinfo broadcastAddressHints {};
|
|
||||||
broadcastAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET;
|
|
||||||
broadcastAddressHints.ai_socktype = SOCK_DGRAM;
|
|
||||||
broadcastAddressHints.ai_protocol = IPPROTO_UDP;
|
|
||||||
|
|
||||||
// create the client socket
|
|
||||||
this->context->socket = socket(
|
|
||||||
broadcastAddressHints.ai_family,
|
|
||||||
broadcastAddressHints.ai_socktype,
|
|
||||||
broadcastAddressHints.ai_protocol
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this->context->socket < 0)
|
|
||||||
throw std::runtime_error("Could not create the socket: " + std::string(strerror(errno)));
|
|
||||||
|
|
||||||
// allow IPv6 multicast loopback so that we can receive our own messages.
|
|
||||||
constexpr int socketLoopback = 1;
|
|
||||||
if (setsockopt(
|
|
||||||
context->socket,
|
|
||||||
IPPROTO_IPV6,
|
|
||||||
IPV6_MULTICAST_LOOP,
|
|
||||||
&socketLoopback,
|
|
||||||
sizeof(socketLoopback)
|
|
||||||
) < 0) {
|
|
||||||
std::cerr << "Failed to set IPV6_MULTICAST_LOOP: " << strerror(errno) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the information for the broadcast local-link address
|
|
||||||
if(const int error = getaddrinfo(
|
|
||||||
address.c_str(),
|
|
||||||
port.c_str(),
|
|
||||||
&broadcastAddressHints,
|
|
||||||
&context->broadcastAddressInfo
|
|
||||||
) != 0)
|
|
||||||
throw std::runtime_error("Could not get the broadcast address: " + std::string(gai_strerror(error)));
|
|
||||||
|
|
||||||
// hints for the bind address
|
|
||||||
addrinfo anyAddressHints {};
|
|
||||||
anyAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET;
|
|
||||||
anyAddressHints.ai_flags = AI_PASSIVE;
|
|
||||||
anyAddressHints.ai_socktype = SOCK_DGRAM;
|
|
||||||
anyAddressHints.ai_protocol = IPPROTO_UDP;
|
|
||||||
|
|
||||||
// get the information for the broadcast local-link address
|
|
||||||
addrinfo *anyAddressInfo;
|
|
||||||
if(const int error = getaddrinfo(
|
|
||||||
nullptr,
|
|
||||||
port.c_str(),
|
|
||||||
&anyAddressHints,
|
|
||||||
&anyAddressInfo
|
|
||||||
) != 0)
|
|
||||||
throw std::runtime_error("Could not get the any address: " + std::string(gai_strerror(error)));
|
|
||||||
|
|
||||||
// bind the socket to the address
|
|
||||||
if (bind(
|
|
||||||
this->context->socket,
|
|
||||||
anyAddressInfo->ai_addr,
|
|
||||||
anyAddressInfo->ai_addrlen
|
|
||||||
) < 0)
|
|
||||||
throw std::runtime_error("Could not bind to the address: " + std::string(strerror(errno)));
|
|
||||||
|
|
||||||
// TODO(Faraphel): should only be enabled in specific case.
|
|
||||||
this->context->me.serverEnabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Manager::loop() {
|
|
||||||
// run an event receiver and sender
|
|
||||||
this->senderThread = std::thread(&Manager::loopSender, this);
|
|
||||||
this->receiverThread = std::thread(&Manager::loopReceiver, this);
|
|
||||||
|
|
||||||
this->senderThread.join();
|
|
||||||
this->receiverThread.join();
|
|
||||||
|
|
||||||
freeaddrinfo(this->context->broadcastAddressInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Manager::loopSender() const {
|
|
||||||
while (true) {
|
|
||||||
std::cout << "[Sender] Handling status: " + std::to_string(static_cast<int>(this->context->me.status)) << std::endl;
|
|
||||||
|
|
||||||
// get the corresponding task class
|
|
||||||
std::shared_ptr<drp::task::BaseTask> task;
|
|
||||||
try {
|
|
||||||
task = this->taskRegistry.at(this->context->me.status);
|
|
||||||
} catch (const std::out_of_range& exception) {
|
|
||||||
std::cerr << "[Sender] Unsupported status." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask the task class to handle the task
|
|
||||||
task->handle(*this->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Manager::loopReceiver() const {
|
|
||||||
// prepare space for the sender address
|
|
||||||
sockaddr_storage fromAddress {};
|
|
||||||
socklen_t fromAddressLength = sizeof(fromAddress);
|
|
||||||
|
|
||||||
std::array<std::uint8_t, drp::packet::base::maxPacketLength> buffer {};
|
|
||||||
|
|
||||||
// client loop
|
|
||||||
while (true) {
|
|
||||||
// receive new data
|
|
||||||
const ssize_t size = recvfrom(
|
|
||||||
this->context->socket,
|
|
||||||
buffer.data(),
|
|
||||||
buffer.size(),
|
|
||||||
0,
|
|
||||||
reinterpret_cast<sockaddr*>(&fromAddress),
|
|
||||||
&fromAddressLength
|
|
||||||
);
|
|
||||||
if (size == -1)
|
|
||||||
throw std::runtime_error("[Receiver] Could not receive the packet: " + std::string(strerror(errno)));
|
|
||||||
|
|
||||||
// deserialize the packet
|
|
||||||
std::vector data(buffer.begin(), buffer.end());
|
|
||||||
const auto packet = drp::packet::base::Packet::deserialize(data);
|
|
||||||
|
|
||||||
// if the packet channel is neither 0 (all) nor the current one, ignore it
|
|
||||||
if (packet.channel != 0 && packet.channel != this->context->me.channel)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// decrypt the packet
|
|
||||||
// TODO(Faraphel): handle exception ?
|
|
||||||
drp::packet::base::PacketContent packetContent = packet.getContent(*this->context);
|
|
||||||
|
|
||||||
// look for a saved peer with the same address
|
|
||||||
auto remotePeer = std::ranges::find_if(
|
|
||||||
this->context->remotePeers,
|
|
||||||
[&](const std::shared_ptr<RemotePeer>& remotePeer) { return
|
|
||||||
remotePeer->addressLength == fromAddressLength and
|
|
||||||
std::memcmp(&fromAddress, &remotePeer->address, fromAddressLength) == 0;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// if found, update the latest connection date
|
|
||||||
if (remotePeer != this->context->remotePeers.end()) {
|
|
||||||
(*remotePeer)->latestConnection = std::chrono::high_resolution_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the corresponding event class
|
|
||||||
std::shared_ptr<drp::event::BaseEvent> event;
|
|
||||||
try {
|
|
||||||
event = this->eventRegistry.at(packetContent.eventType);
|
|
||||||
} catch (const std::out_of_range& exception) {
|
|
||||||
std::cerr << "[Receiver] Unsupported event type." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "[Receiver] handling event: " << static_cast<std::uint8_t>(packetContent.eventType) << std::endl;
|
|
||||||
|
|
||||||
// ask the event class to handle the event
|
|
||||||
event->handle(
|
|
||||||
*this->context,
|
|
||||||
packetContent.data,
|
|
||||||
fromAddress,
|
|
||||||
fromAddressLength
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "Context.hpp"
|
|
||||||
#include "behavior/events/types.hpp"
|
|
||||||
#include "behavior/events/base/BaseEvent.hpp"
|
|
||||||
#include "behavior/tasks/types.hpp"
|
|
||||||
#include "behavior/tasks/base/BaseTask.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Manager.
|
|
||||||
* Manage how should the program behave depending on its current state, or the message it receive.
|
|
||||||
*/
|
|
||||||
// TODO(Faraphel): could be split in two part.
|
|
||||||
class Manager {
|
|
||||||
public:
|
|
||||||
Manager(const std::string& address, const std::string& port, bool useIpv6 = false);
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
void loopSender() const;
|
|
||||||
void loopReceiver() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::thread senderThread; /// the thread sending communication
|
|
||||||
std::thread receiverThread; /// the thread receiving communication
|
|
||||||
|
|
||||||
std::map<drp::event::EventType, std::shared_ptr<drp::event::BaseEvent>> eventRegistry; /// hold the event to call depending on the event type
|
|
||||||
std::map<drp::task::TaskType, std::shared_ptr<drp::task::BaseTask>> taskRegistry; /// hold the task to call depending on the server status
|
|
||||||
|
|
||||||
std::shared_ptr<Context> context; /// context used between the events types
|
|
||||||
};
|
|
|
@ -2,10 +2,10 @@
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "argparse/argparse.hpp"
|
#include "argparse/argparse.hpp"
|
||||||
#include "Manager.hpp"
|
#include "managers/Manager.hpp"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(const int argc, char* argv[]) {
|
||||||
// initialize the mpg123 library
|
// initialize the mpg123 library
|
||||||
if (mpg123_init() != MPG123_OK)
|
if (mpg123_init() != MPG123_OK)
|
||||||
throw std::runtime_error("Error while initializing mpg123.");
|
throw std::runtime_error("Error while initializing mpg123.");
|
||||||
|
@ -26,14 +26,14 @@ int main(int argc, char* argv[]) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eventManager = Manager(
|
auto manager = drp::managers::Manager(
|
||||||
parser.get<std::string>("--host"),
|
parser.get<std::string>("--host"),
|
||||||
parser.get<std::string>("--port"),
|
parser.get<std::string>("--port"),
|
||||||
parser.get<bool>("-6")
|
parser.get<bool>("-6")
|
||||||
);
|
);
|
||||||
eventManager.loop();
|
manager.loop();
|
||||||
|
|
||||||
// terminate the libraries
|
// close the libraries
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
mpg123_exit();
|
mpg123_exit();
|
||||||
|
|
||||||
|
|
112
source/managers/Manager.cpp
Normal file
112
source/managers/Manager.cpp
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#include "Manager.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <ostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <random>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "behavior/events/audio/AudioEvent.hpp"
|
||||||
|
#include "behavior/tasks/server/ServerTask.hpp"
|
||||||
|
#include "utils/crypto/aes/AesKey.hpp"
|
||||||
|
#include "utils/crypto/rsa/RsaKeyPair.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
|
||||||
|
Manager::Manager(const std::string& address, const std::string& port, const bool useIpv6) {
|
||||||
|
std::cout << "Broadcast address: " << address << ":" << port << " (" << (useIpv6 ? "IPv6" : "IPv4") << ")" << std::endl;
|
||||||
|
|
||||||
|
// hints for the communication
|
||||||
|
addrinfo broadcastAddressHints {};
|
||||||
|
broadcastAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET;
|
||||||
|
broadcastAddressHints.ai_socktype = SOCK_DGRAM;
|
||||||
|
broadcastAddressHints.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
// create the client socket
|
||||||
|
const int sock = socket(
|
||||||
|
broadcastAddressHints.ai_family,
|
||||||
|
broadcastAddressHints.ai_socktype,
|
||||||
|
broadcastAddressHints.ai_protocol
|
||||||
|
);
|
||||||
|
if (sock < 0)
|
||||||
|
throw std::runtime_error("Could not create the socket: " + std::string(strerror(errno)));
|
||||||
|
|
||||||
|
// allow IPv6 multicast loopback so that we can receive our own messages.
|
||||||
|
constexpr int socketLoopback = 1;
|
||||||
|
if (setsockopt(
|
||||||
|
sock,
|
||||||
|
IPPROTO_IPV6,
|
||||||
|
IPV6_MULTICAST_LOOP,
|
||||||
|
&socketLoopback,
|
||||||
|
sizeof(socketLoopback)
|
||||||
|
) < 0) {
|
||||||
|
std::cerr << "Failed to set IPV6_MULTICAST_LOOP: " << strerror(errno) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the information for the broadcast local-link address
|
||||||
|
addrinfo* broadcastAddressInfo = nullptr;
|
||||||
|
if (const int error = getaddrinfo(
|
||||||
|
address.c_str(),
|
||||||
|
port.c_str(),
|
||||||
|
&broadcastAddressHints,
|
||||||
|
&broadcastAddressInfo
|
||||||
|
) != 0)
|
||||||
|
throw std::runtime_error("Could not get the broadcast address: " + std::string(gai_strerror(error)));
|
||||||
|
|
||||||
|
// hints for the bind address
|
||||||
|
addrinfo anyAddressHints {};
|
||||||
|
anyAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET;
|
||||||
|
anyAddressHints.ai_flags = AI_PASSIVE;
|
||||||
|
anyAddressHints.ai_socktype = SOCK_DGRAM;
|
||||||
|
anyAddressHints.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
// get the information for the broadcast local-link address
|
||||||
|
addrinfo *anyAddressInfo;
|
||||||
|
if (const int error = getaddrinfo(
|
||||||
|
nullptr,
|
||||||
|
port.c_str(),
|
||||||
|
&anyAddressHints,
|
||||||
|
&anyAddressInfo
|
||||||
|
) != 0)
|
||||||
|
throw std::runtime_error("Could not get the any address: " + std::string(gai_strerror(error)));
|
||||||
|
|
||||||
|
// bind the socket to the address
|
||||||
|
if (bind(
|
||||||
|
sock,
|
||||||
|
anyAddressInfo->ai_addr,
|
||||||
|
anyAddressInfo->ai_addrlen
|
||||||
|
) < 0)
|
||||||
|
throw std::runtime_error("Could not bind to the address: " + std::string(strerror(errno)));
|
||||||
|
|
||||||
|
// create the context
|
||||||
|
this->context = std::make_shared<Context>(sock, broadcastAddressInfo);
|
||||||
|
// TODO(Faraphel): should only be enabled if it can really emit sound.
|
||||||
|
this->context->me.serverEnabled = true;
|
||||||
|
|
||||||
|
// create the sub-managers.
|
||||||
|
this->sendManager = std::make_unique<SendManager>(context);
|
||||||
|
this->receiveManager = std::make_unique<ReceiveManager>(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::~Manager() {
|
||||||
|
freeaddrinfo(this->context->broadcastAddressInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Manager::loop() {
|
||||||
|
// run an event receiver and sender
|
||||||
|
std::thread senderThread(&SendManager::loop, this->sendManager.get());
|
||||||
|
std::thread receiverThread(&ReceiveManager::loop, this->receiveManager.get());
|
||||||
|
|
||||||
|
senderThread.join();
|
||||||
|
receiverThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
32
source/managers/Manager.hpp
Normal file
32
source/managers/Manager.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Context.hpp"
|
||||||
|
#include "managers/ReceiveManager.hpp"
|
||||||
|
#include "managers/SendManager.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Manager.
|
||||||
|
* serve as the mainloop of the program.
|
||||||
|
*/
|
||||||
|
class Manager {
|
||||||
|
public:
|
||||||
|
Manager(const std::string& address, const std::string& port, bool useIpv6 = false);
|
||||||
|
~Manager();
|
||||||
|
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Context> context; /// context used between the events types
|
||||||
|
|
||||||
|
std::unique_ptr<SendManager> sendManager;
|
||||||
|
std::unique_ptr<ReceiveManager> receiveManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
101
source/managers/ReceiveManager.cpp
Normal file
101
source/managers/ReceiveManager.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#include "ReceiveManager.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "behavior/events/audio/AudioEvent.hpp"
|
||||||
|
#include "behavior/events/info/InfoEvent.hpp"
|
||||||
|
#include "behavior/events/pong/PongEvent.hpp"
|
||||||
|
#include "behavior/events/search/SearchEvent.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
|
||||||
|
ReceiveManager::ReceiveManager(const std::shared_ptr<Context>& context) {
|
||||||
|
this->context = context;
|
||||||
|
|
||||||
|
// register the different events type
|
||||||
|
this->registry = {
|
||||||
|
{event::EventType::PONG, std::make_shared<event::PongEvent>()},
|
||||||
|
{event::EventType::SEARCH, std::make_shared<event::SearchEvent>()},
|
||||||
|
{event::EventType::INFO, std::make_shared<event::InfoEvent>()},
|
||||||
|
{event::EventType::AUDIO, std::make_shared<event::AudioEvent>()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ReceiveManager::run() const {
|
||||||
|
// prepare space for the sender address
|
||||||
|
sockaddr_storage fromAddress {};
|
||||||
|
socklen_t fromAddressLength = sizeof(fromAddress);
|
||||||
|
|
||||||
|
std::array<std::uint8_t, packet::base::maxPacketLength> buffer {};
|
||||||
|
|
||||||
|
// receive new data
|
||||||
|
const ssize_t size = recvfrom(
|
||||||
|
this->context->socket,
|
||||||
|
buffer.data(),
|
||||||
|
buffer.size(),
|
||||||
|
0,
|
||||||
|
reinterpret_cast<sockaddr*>(&fromAddress),
|
||||||
|
&fromAddressLength
|
||||||
|
);
|
||||||
|
if (size == -1)
|
||||||
|
throw std::runtime_error("[Receiver] Could not receive the packet: " + std::string(strerror(errno)));
|
||||||
|
|
||||||
|
// deserialize the packet
|
||||||
|
std::vector data(buffer.begin(), buffer.end());
|
||||||
|
const auto packet = drp::packet::base::Packet::deserialize(data);
|
||||||
|
|
||||||
|
// if the packet channel is neither 0 (all) nor the current one, ignore it
|
||||||
|
if (packet.channel != 0 && packet.channel != this->context->me.channel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// decrypt the packet
|
||||||
|
// TODO(Faraphel): handle exception ?
|
||||||
|
drp::packet::base::PacketContent packetContent = packet.getContent(*this->context);
|
||||||
|
|
||||||
|
// look for a saved peer with the same address
|
||||||
|
auto remotePeer = std::ranges::find_if(
|
||||||
|
this->context->remotePeers,
|
||||||
|
[&](const std::shared_ptr<RemotePeer>& remotePeer) { return
|
||||||
|
remotePeer->addressLength == fromAddressLength and
|
||||||
|
std::memcmp(&fromAddress, &remotePeer->address, fromAddressLength) == 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// if found, update the latest connection date
|
||||||
|
if (remotePeer != this->context->remotePeers.end())
|
||||||
|
(*remotePeer)->latestConnection = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// get the corresponding event class
|
||||||
|
std::shared_ptr<event::BaseEvent> event;
|
||||||
|
try {
|
||||||
|
event = this->registry.at(packetContent.eventType);
|
||||||
|
} catch (const std::out_of_range& exception) {
|
||||||
|
std::cerr << "[Receiver] Unsupported event type: " << std::to_string(static_cast<int>(packetContent.eventType)) << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[Receiver] handling event: " << std::to_string(static_cast<int>(packetContent.eventType)) << std::endl;
|
||||||
|
|
||||||
|
// ask the event class to handle the event
|
||||||
|
try {
|
||||||
|
event->handle(
|
||||||
|
*this->context,
|
||||||
|
packetContent.data,
|
||||||
|
fromAddress,
|
||||||
|
fromAddressLength
|
||||||
|
);
|
||||||
|
} catch (const std::exception& exception) {
|
||||||
|
std::cerr << "[Receiver] Unhandled exception: " << exception.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveManager::loop() const {
|
||||||
|
while (true)
|
||||||
|
this->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
29
source/managers/ReceiveManager.hpp
Normal file
29
source/managers/ReceiveManager.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "behavior/events/types.hpp"
|
||||||
|
#include "behavior/events/base/BaseEvent.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ReceiveManager class.
|
||||||
|
* Handle everything related to receiving messages.
|
||||||
|
*/
|
||||||
|
class ReceiveManager {
|
||||||
|
public:
|
||||||
|
explicit ReceiveManager(const std::shared_ptr<Context>& context);
|
||||||
|
|
||||||
|
void run() const;
|
||||||
|
[[noreturn]] void loop() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Context> context;
|
||||||
|
std::map<event::EventType, std::shared_ptr<event::BaseEvent>> registry;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
52
source/managers/SendManager.cpp
Normal file
52
source/managers/SendManager.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "SendManager.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "behavior/tasks/client/ClientTask.hpp"
|
||||||
|
#include "behavior/tasks/server/ServerTask.hpp"
|
||||||
|
#include "behavior/tasks/undefined/UndefinedTask.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
|
||||||
|
SendManager::SendManager(const std::shared_ptr<Context>& context) {
|
||||||
|
this->context = context;
|
||||||
|
|
||||||
|
// register the different tasks type
|
||||||
|
this->registry = {
|
||||||
|
{task::TaskType::UNDEFINED, std::make_shared<task::UndefinedTask>()},
|
||||||
|
{task::TaskType::CLIENT, std::make_shared<task::ClientTask>()},
|
||||||
|
{task::TaskType::SERVER, std::make_shared<task::ServerTask>()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SendManager::run() const {
|
||||||
|
std::cout << "[Sender] Handling status: " + std::to_string(static_cast<int>(this->context->me.status)) << std::endl;
|
||||||
|
|
||||||
|
// get the corresponding task class
|
||||||
|
std::shared_ptr<task::BaseTask> task;
|
||||||
|
try {
|
||||||
|
task = this->registry.at(this->context->me.status);
|
||||||
|
} catch (const std::out_of_range& exception) {
|
||||||
|
std::cerr << "[Sender] Unsupported status: " << std::to_string(static_cast<int>(this->context->me.status)) << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask the task class to handle the task
|
||||||
|
try {
|
||||||
|
task->handle(*this->context);
|
||||||
|
} catch (const std::exception& exception) {
|
||||||
|
std::cerr << "[Sender] Unhandled exception: " << exception.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SendManager::loop() const {
|
||||||
|
while (true)
|
||||||
|
this->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
30
source/managers/SendManager.hpp
Normal file
30
source/managers/SendManager.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "behavior/tasks/types.hpp"
|
||||||
|
#include "behavior/tasks/base/BaseTask.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace drp::managers {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SendManager class.
|
||||||
|
* Handle everything related to sending messages.
|
||||||
|
*/
|
||||||
|
class SendManager {
|
||||||
|
public:
|
||||||
|
explicit SendManager(const std::shared_ptr<Context>& context);
|
||||||
|
|
||||||
|
void run() const;
|
||||||
|
[[noreturn]] void loop() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Context> context;
|
||||||
|
std::map<task::TaskType, std::shared_ptr<task::BaseTask>> registry;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -95,7 +95,15 @@ int mainSerialize() {
|
||||||
|
|
||||||
|
|
||||||
int mainRsaSerialize() {
|
int mainRsaSerialize() {
|
||||||
|
// create a key pair
|
||||||
|
drp::util::crypto::RsaKeyPair keyPair(2048);
|
||||||
|
|
||||||
|
// create an object
|
||||||
Peer peer;
|
Peer peer;
|
||||||
|
peer.channel = 7;
|
||||||
|
peer.id = 253;
|
||||||
|
|
||||||
|
// serialize it
|
||||||
auto serializedPeer = peer.serialize();
|
auto serializedPeer = peer.serialize();
|
||||||
|
|
||||||
std::cout << "serialized: ";
|
std::cout << "serialized: ";
|
||||||
|
@ -103,7 +111,26 @@ int mainRsaSerialize() {
|
||||||
std::cout << std::to_string(byte) << "-";
|
std::cout << std::to_string(byte) << "-";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
const auto deserializedPeer = Peer::deserialize(serializedPeer);
|
// encrypt it
|
||||||
|
const std::vector<std::uint8_t> encryptedSerializedPeer = keyPair.getPublicKey().encrypt(serializedPeer);
|
||||||
|
|
||||||
|
std::cout << "encrypted: ";
|
||||||
|
for (const auto& byte : encryptedSerializedPeer)
|
||||||
|
std::cout << std::to_string(byte) << "-";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// decrypt it
|
||||||
|
std::vector<std::uint8_t> decryptedSerializedPeer = keyPair.getPrivateKey().decrypt(encryptedSerializedPeer);
|
||||||
|
|
||||||
|
std::cout << "decrypted: ";
|
||||||
|
for (const auto& byte : decryptedSerializedPeer)
|
||||||
|
std::cout << std::to_string(byte) << "-";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
const auto deserializedPeer = Peer::deserialize(decryptedSerializedPeer);
|
||||||
|
|
||||||
|
std::cout << "peer id: " << std::to_string(deserializedPeer.id) << std::endl;
|
||||||
|
std::cout << "peer channel: " << std::to_string(deserializedPeer.channel) << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +140,7 @@ int main_test() {
|
||||||
// mainAes();
|
// mainAes();
|
||||||
// mainRsa();
|
// mainRsa();
|
||||||
// mainSerialize();
|
// mainSerialize();
|
||||||
// mainRsaSerialize();
|
mainRsaSerialize();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue