diff --git a/LICENSE.md b/LICENSE.md index 3cdb0c6..c90865d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -28,7 +28,7 @@ Ce logiciel est distribué tel quel, sans aucune garantie de quelque nature que ## VI. Glossaire -fork : projet se basant sur le code code source d'un logiciel déjà existant. +fork : projet se basant sur le code source d'un logiciel déjà existant. --- diff --git a/source/Context.hpp b/source/Context.hpp index 7080848..d1ad568 100644 --- a/source/Context.hpp +++ b/source/Context.hpp @@ -13,6 +13,9 @@ struct Context { std::shared_ptr server = nullptr; Peer me; - std::map> remotePeers {}; + std::map< + std::uint32_t, + std::shared_ptr + > remotePeers {}; std::chrono::high_resolution_clock::time_point latestPeerDiscovery; }; diff --git a/source/EventManager.cpp b/source/EventManager.cpp index d94165b..b8f096f 100644 --- a/source/EventManager.cpp +++ b/source/EventManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "events/types.hpp" @@ -63,6 +64,19 @@ EventManager::EventManager() { ) != 0) throw std::runtime_error("[Sender] Could not get the address: " + std::string(gai_strerror(error))); + // generate a random identifier for ourselves + std::random_device randomDevice; + std::mt19937 randomGenerator(randomDevice()); + + std::uniform_int_distribution distribution( + 1, + std::numeric_limits::max() + ); + this->context.me.id = distribution(randomGenerator); + + // TODO(Faraphel): should only be enabled in specific case. + this->context.me.serverEnabled = true; + // define the time of the latest discovery this->context.latestPeerDiscovery = std::chrono::high_resolution_clock::now(); } @@ -134,7 +148,7 @@ void EventManager::loopReceiver() { // TODO(Faraphel): port as argument addrinfo* senderInfo; if(getaddrinfo( - nullptr, // hostname + "0.0.0.0", // hostname "5650", // port &addressHints, &senderInfo @@ -186,7 +200,7 @@ void EventManager::loopReceiver() { event->handle( this->context, packetContent, - reinterpret_cast(&fromAddress), + fromAddress, fromAddressLength ); } diff --git a/source/RemotePeer.hpp b/source/RemotePeer.hpp index 9d639c5..df72d3a 100644 --- a/source/RemotePeer.hpp +++ b/source/RemotePeer.hpp @@ -10,9 +10,11 @@ * Contains common information about a certain peer. */ struct Peer { + std::uint32_t id = 0; + bool serverEnabled = false; drp::task::TaskType status = drp::task::TaskType::UNDEFINED; - uint8_t channel = 0; + std::uint8_t channel = 0; std::chrono::high_resolution_clock::duration latencyAverage = std::chrono::high_resolution_clock::duration::max(); }; @@ -23,8 +25,9 @@ struct Peer { */ struct RemotePeer { // communication - sockaddr address {}; + sockaddr_storage address {}; socklen_t addressLength = 0; + std::chrono::high_resolution_clock::duration latency = std::chrono::high_resolution_clock::duration::max(); // information diff --git a/source/events/audio/AudioEvent.cpp b/source/events/audio/AudioEvent.cpp index 8567edd..ed88304 100644 --- a/source/events/audio/AudioEvent.cpp +++ b/source/events/audio/AudioEvent.cpp @@ -32,8 +32,8 @@ AudioEvent::~AudioEvent() { void AudioEvent::handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, - socklen_t fromAddressLength + const sockaddr_storage& fromAddress, + const socklen_t fromAddressLength ) { // get the audio data in the content packet::AudioPacketData audioData; diff --git a/source/events/audio/AudioEvent.hpp b/source/events/audio/AudioEvent.hpp index 369a996..cded46c 100644 --- a/source/events/audio/AudioEvent.hpp +++ b/source/events/audio/AudioEvent.hpp @@ -23,7 +23,7 @@ public: void handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, socklen_t fromAddressLength ) override; diff --git a/source/events/base/BaseEvent.hpp b/source/events/base/BaseEvent.hpp index 1611e06..0b71de2 100644 --- a/source/events/base/BaseEvent.hpp +++ b/source/events/base/BaseEvent.hpp @@ -13,7 +13,7 @@ public: virtual void handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, socklen_t fromAddressLength ) = 0; }; diff --git a/source/events/info/InfoEvent.cpp b/source/events/info/InfoEvent.cpp index 8f2922e..2a4de06 100644 --- a/source/events/info/InfoEvent.cpp +++ b/source/events/info/InfoEvent.cpp @@ -10,17 +10,21 @@ namespace drp::event { void InfoEvent::handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, const socklen_t fromAddressLength ) { - // check if the peer address is already in the map - std::shared_ptr remotePeer; - auto iterator = context.remotePeers.find(*fromAddress); + // get the peer information + Peer peer; + std::memcpy(&peer, &content, sizeof(Peer)); + // check if the peer address is already in the map + const auto iterator = context.remotePeers.find(peer.id); + + std::shared_ptr remotePeer; if (iterator == context.remotePeers.end()) { // if not found, create a new peer remotePeer = std::make_shared(); - remotePeer->address = *fromAddress; + remotePeer->address = fromAddress; remotePeer->addressLength = fromAddressLength; // update the latest discovery time context.latestPeerDiscovery = std::chrono::high_resolution_clock::now(); @@ -29,13 +33,11 @@ void InfoEvent::handle( remotePeer = iterator->second; } - // save the remote peer information - std::memcpy(&remotePeer->information, &content, sizeof(Peer)); - // TODO(Faraphel): interpret the timestamp and calculate average ping // save it in the peers list - context.remotePeers[remotePeer->address] = remotePeer; + remotePeer->information = peer; + context.remotePeers[peer.id] = remotePeer; } diff --git a/source/events/info/InfoEvent.hpp b/source/events/info/InfoEvent.hpp index cd5b6a0..9ee260d 100644 --- a/source/events/info/InfoEvent.hpp +++ b/source/events/info/InfoEvent.hpp @@ -11,7 +11,7 @@ public: void handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, socklen_t fromAddressLength ) override; }; diff --git a/source/events/pong/PongEvent.cpp b/source/events/pong/PongEvent.cpp index 751ab6f..4bfbace 100644 --- a/source/events/pong/PongEvent.cpp +++ b/source/events/pong/PongEvent.cpp @@ -9,8 +9,8 @@ namespace drp::event { void PongEvent::handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, - socklen_t fromAddressLength + const sockaddr_storage& fromAddress, + const socklen_t fromAddressLength ) { std::cout << "[Receiver] Pong." << std::endl; } diff --git a/source/events/pong/PongEvent.hpp b/source/events/pong/PongEvent.hpp index 2a629e9..df720a5 100644 --- a/source/events/pong/PongEvent.hpp +++ b/source/events/pong/PongEvent.hpp @@ -11,7 +11,7 @@ public: void handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, socklen_t fromAddressLength ) override; }; diff --git a/source/events/search/SearchEvent.cpp b/source/events/search/SearchEvent.cpp index 1165723..359dbed 100644 --- a/source/events/search/SearchEvent.cpp +++ b/source/events/search/SearchEvent.cpp @@ -16,7 +16,7 @@ namespace drp { void event::SearchEvent::handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, const socklen_t fromAddressLength ) { packet::GenericPacket packet {}; @@ -39,7 +39,7 @@ void event::SearchEvent::handle( &packet, sizeof(packet), 0, - fromAddress, + reinterpret_cast(&fromAddress), fromAddressLength ) == -1) { std::cerr << "[Receiver] Could not send information: " << strerror(errno) << std::endl; diff --git a/source/events/search/SearchEvent.hpp b/source/events/search/SearchEvent.hpp index fadd7c4..1e46c3d 100644 --- a/source/events/search/SearchEvent.hpp +++ b/source/events/search/SearchEvent.hpp @@ -10,7 +10,7 @@ public: void handle( Context& context, const packet::GenericPacketContent& content, - sockaddr* fromAddress, + const sockaddr_storage& fromAddress, socklen_t fromAddressLength ) override; }; diff --git a/source/tasks/undefined/UndefinedTask.cpp b/source/tasks/undefined/UndefinedTask.cpp index 2cfdda9..2bf20d9 100644 --- a/source/tasks/undefined/UndefinedTask.cpp +++ b/source/tasks/undefined/UndefinedTask.cpp @@ -4,7 +4,10 @@ #include #include #include +#include #include +#include +#include #include #include "../../Context.hpp" @@ -17,63 +20,51 @@ namespace drp::task { void UndefinedTask::handle(Context& context) { - // TODO(Faraphel): If .status is UNDEFINED, look for a server. - // if alone, become a server (if can emit). - // if everyone is UNKNOWN, elect a server (easiest to join / highest mac address, etc...) - // if a server is found, become a client. + // search if a server is available among the peer. + const auto& server = std::ranges::find_if( + context.remotePeers, + [&](const auto& peer) { return peer.second->information.status == TaskType::SERVER; } + ); - // check if no more peers have been found. + // if a server have been found, use it + if (server != context.remotePeers.end()) { + // if a server have been found, use it + context.server = server->second; + context.me.status = TaskType::CLIENT; + return; + } + + // wait that no more new peers are being discovered if ( std::chrono::high_resolution_clock::now() - context.latestPeerDiscovery > std::chrono::milliseconds(5000) ) { - // verify if there are peers - // TODO(Faraphel): the map is never empty since there is a least the local client - if (context.remotePeers.empty()) { - // if we are alone in the network + // otherwise, become the server if we have the highest ID. + // TODO(Faraphel): should use the machine with the lowest average ping + if (context.me.serverEnabled) { + // find the remote peer with the highest id that can be a server + const auto serverCandidate = std::max_element( + context.remotePeers.begin(), + context.remotePeers.end(), + [&](auto& remotePeer1, auto& remotePeer2) { + return ( + (remotePeer1.second->information.serverEnabled ? remotePeer1.first : 0) < + (remotePeer2.second->information.serverEnabled ? remotePeer2.first : 0) + ); + } + ); - // check if we are capable of being a server - if (!context.me.serverEnabled) + // check if we are this peer + if (context.me.id == serverCandidate->first) { + std::cout << "becoming server..." << std::endl; + // set ourselves as the server + context.server = serverCandidate->second; + context.me.status = TaskType::SERVER; return; - - // set ourselves as the server - context.server = nullptr; - context.me.status = TaskType::SERVER; - return; - } - - // look for a server among the peers - const auto& server = std::ranges::find_if( - context.remotePeers, - [&](const auto& peer) { return peer.second->information.status == TaskType::SERVER; } - ); - - if (server != context.remotePeers.end()) { - // if a server have been found, use it - context.server = server->second; - context.me.status = TaskType::CLIENT; - return; - } - - // TODO(Faraphel): check if we have the lowest average ping out of all the peers. If yes, become the server. - // Others peers will connect to us on their next loop. - // TODO(Faraphel): use a unique ID instead ? - if (!context.me.serverEnabled) - return; - - // check we have the lowest latency out of all the peers - if (std::all_of( - context.remotePeers.begin(), - context.remotePeers.end(), - [&](const auto& peer) { - return peer.second->information.latencyAverage > context.me.latencyAverage; } - )) { - // set ourselves as the server - context.server = nullptr; - context.me.status = TaskType::SERVER; - return; } + + // TODO(Faraphel): sleep 1s } // prepare a search message