M2-PT-DRP/source/managers/Manager.cpp

112 lines
No EOL
3.5 KiB
C++

#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();
}
}