112 lines
No EOL
3.5 KiB
C++
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();
|
|
}
|
|
|
|
|
|
} |