diff options
-rw-r--r-- | include/erebos/network.h | 3 | ||||
-rw-r--r-- | src/main.cpp | 11 | ||||
-rw-r--r-- | src/network.cpp | 42 | ||||
-rw-r--r-- | test/sync.test | 49 |
4 files changed, 102 insertions, 3 deletions
diff --git a/include/erebos/network.h b/include/erebos/network.h index ed31823..66edfa4 100644 --- a/include/erebos/network.h +++ b/include/erebos/network.h @@ -14,6 +14,7 @@ using std::vector; using std::unique_ptr; class ServerConfig; +class Peer; class Server { @@ -33,6 +34,8 @@ public: template<class S> S & svc(); class PeerList & peerList() const; + void addPeer(const string & node) const; + void addPeer(const string & node, const string & service) const; struct Peer; private: diff --git a/src/main.cpp b/src/main.cpp index 63b78dd..f33bcc4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -328,6 +328,16 @@ void stopServer(const vector<string> &) server.reset(); } +void peerAdd(const vector<string> & args) +{ + if (args.size() == 1) + server->addPeer(args.at(0)); + else if (args.size() == 2) + server->addPeer(args.at(0), args.at(1)); + else + throw invalid_argument("usage: peer-add <node> [<port>]"); +} + void sharedStateGet(const vector<string> &) { ostringstream ss; @@ -530,6 +540,7 @@ vector<Command> commands = { { "create-identity", createIdentity }, { "start-server", startServer }, { "stop-server", stopServer }, + { "peer-add", peerAdd }, { "shared-state-get", sharedStateGet }, { "shared-state-wait", sharedStateWait }, { "watch-local-identity", watchLocalIdentity }, diff --git a/src/network.cpp b/src/network.cpp index ecf7ca0..226095b 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -11,6 +11,9 @@ #include <arpa/inet.h> #include <ifaddrs.h> #include <net/if.h> +#include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> using std::get; @@ -70,6 +73,43 @@ PeerList & Server::peerList() const return p->plist; } +void Server::addPeer(const string & node) const +{ + return addPeer(node, to_string(Priv::discoveryPort)); +} + +void Server::addPeer(const string & node, const string & service) const +{ + addrinfo hints {}; + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + addrinfo *aptr; + + int r = getaddrinfo(node.c_str(), service.c_str(), &hints, &aptr); + if (r != 0) + throw runtime_error(string("Server::addPeer: getaddrinfo failed: ") + gai_strerror(r)); + + unique_ptr<addrinfo, void(*)(addrinfo*)> result { aptr, &freeaddrinfo }; + + for (addrinfo * rp = result.get(); rp != nullptr; rp = rp->ai_next) { + if (rp->ai_family == AF_INET6) { + Peer & peer = p->getPeer(*(sockaddr_in6 *)rp->ai_addr); + + vector<TransportHeader::Item> header; + { + shared_lock lock(p->selfMutex); + header.push_back(TransportHeader::Item { + TransportHeader::Type::AnnounceSelf, *p->self.ref() }); + } + peer.send(header, {}, false); + return; + } + } + + throw runtime_error("Server::addPeer: no suitable peer address found"); +} + Peer::Peer(const shared_ptr<Priv> & p): p(p) {} Peer::~Peer() = default; @@ -424,6 +464,8 @@ bool Server::Priv::isSelfAddress(const sockaddr_in6 & paddr) Server::Peer & Server::Priv::getPeer(const sockaddr_in6 & paddr) { + scoped_lock lock(dataMutex); + for (auto & peer : peers) if (memcmp(&peer->addr, &paddr, sizeof paddr) == 0) return *peer; diff --git a/test/sync.test b/test/sync.test index 3cc7cba..91e8f08 100644 --- a/test/sync.test +++ b/test/sync.test @@ -20,9 +20,10 @@ test: /peer 1 id Device1 Owner/ send "attach-to 1" to p2 - expect /attach-request 1 ([0-9]*)/ from p1 capture code1 - expect /attach-response 1 ([0-9]*)/ from p2 capture code2 - guard (code1 == code2) + local: + expect /attach-request 1 ([0-9]*)/ from p1 capture code1 + expect /attach-response 1 ([0-9]*)/ from p2 capture code2 + guard (code1 == code2) send "attach-accept 1" to p1 send "attach-accept 1" to p2 @@ -48,3 +49,45 @@ test: expect /shared-state-get (.*)/ from p1 capture p1state send "shared-state-wait $p1state" to p2 expect /shared-state-wait $p1state/ from p2 + + subnet s + spawn on s as p3 + + with p3: + send "create-identity Device3" + send "watch-local-identity" + send "watch-shared-identity" + send "start-server" + + send "peer-add ${p1.node.ip}" + + expect: + /local-identity Device3/ + /peer 1 addr ${p1.node.ip} 29665/ + /peer 1 id Device1 .*/ + + expect from p1: + /peer 2 addr ${p3.node.ip} 29665/ + /peer 2 id Device3/ + + send "attach-to 1" to p3 + local: + expect /attach-request 2 ([0-9]*)/ from p1 capture code1 + expect /attach-response 1 ([0-9]*)/ from p3 capture code2 + guard (code1 == code2) + + send "attach-accept 2" to p1 + send "attach-accept 1" to p3 + + expect /local-identity Device3 NewOwner3/ from p3 + expect /shared-identity NewOwner3/ from p3 + + send "update-shared-identity NewOwner4" to p3 + expect /shared-identity NewOwner4/ from p1 + expect /shared-identity NewOwner4/ from p2 + expect /shared-identity NewOwner4/ from p3 + + send "update-shared-identity NewOwner5" to p2 + expect /shared-identity NewOwner5/ from p1 + expect /shared-identity NewOwner5/ from p2 + expect /shared-identity NewOwner5/ from p3 |