diff --git a/core/Blob.hpp b/core/Blob.hpp index 007df037b..e3e824e8d 100644 --- a/core/Blob.hpp +++ b/core/Blob.hpp @@ -115,6 +115,12 @@ struct UniqueID static_assert(sizeof(SHA384Hash) == 48,"SHA384Hash contains unnecessary padding"); static_assert(sizeof(UniqueID) == 16,"UniqueID contains unnecessary padding"); +template +struct Blob +{ + uint8_t data[S]; +}; + } // namespace ZeroTier #endif diff --git a/core/Node.cpp b/core/Node.cpp index b4cfd786e..7ac0832e3 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -58,12 +58,6 @@ struct _NodeObjects Topology topology; }; -struct _sortPeerPtrsByAddress -{ - ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const - { return (a->address() < b->address()); } -}; - } // anonymous namespace Node::Node( @@ -152,6 +146,7 @@ Node::Node( Node::~Node() { ZT_SPEW("node destructor run"); + m_networks_l.lock(); m_networks_l.unlock(); m_networks.clear(); @@ -367,9 +362,7 @@ ZT_ResultCode Node::multicastUnsubscribe( } uint64_t Node::address() const -{ - return RR->identity.address().toInt(); -} +{ return RR->identity.address().toInt(); } void Node::status(ZT_NodeStatus *status) const { @@ -380,88 +373,109 @@ void Node::status(ZT_NodeStatus *status) const status->online = m_online ? 1 : 0; } +struct p_ZT_PeerListPrivate : public ZT_PeerList +{ + // Actual containers for the memory, hidden from external users. + std::vector< ZT_Peer > p_peers; + std::list< std::vector > p_paths; + std::list< Identity > p_identities; + std::list< Blob > p_locators; +}; +static void p_peerListFreeFunction(const void *pl) +{ + if (pl) + delete reinterpret_cast(const_cast(pl)); +} + +struct p_sortPeerPtrsByAddress +{ + ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept + { return (a->address() < b->address()); } +}; + ZT_PeerList *Node::peers() const { - Vector< SharedPtr< Peer > > peers, rootPeers; - RR->topology->allPeers(peers, rootPeers); + p_ZT_PeerListPrivate *pl = nullptr; + try { + pl = new p_ZT_PeerListPrivate; + pl->freeFunction = p_peerListFreeFunction; - std::sort(peers.begin(), peers.end(), _sortPeerPtrsByAddress()); + Vector< SharedPtr< Peer > > peers, rootPeers; + RR->topology->allPeers(peers, rootPeers); + std::sort(peers.begin(), peers.end(), p_sortPeerPtrsByAddress()); + std::sort(rootPeers.begin(), rootPeers.end()); + int64_t now = m_now; - const unsigned int bufSize = - sizeof(ZT_PeerList) + - (sizeof(ZT_Peer) * peers.size()) + - ((sizeof(ZT_Path) * ZT_MAX_PEER_NETWORK_PATHS) * peers.size()) + - (sizeof(Identity) * peers.size()) + - (ZT_LOCATOR_MARSHAL_SIZE_MAX * peers.size()); - char *buf = (char *)malloc(bufSize); - if (!buf) - return nullptr; - Utils::zero(buf, bufSize); - ZT_PeerList *pl = reinterpret_cast(buf); - buf += sizeof(ZT_PeerList); - pl->freeFunction = reinterpret_cast(free); - pl->peers = reinterpret_cast(buf); - buf += sizeof(ZT_Peer) * peers.size(); - ZT_Path *peerPath = reinterpret_cast(buf); - buf += (sizeof(ZT_Path) * ZT_MAX_PEER_NETWORK_PATHS) * peers.size(); - Identity *identities = reinterpret_cast(buf); - buf += sizeof(Identity) * peers.size(); - uint8_t *locatorBuf = reinterpret_cast(buf); + for (Vector< SharedPtr< Peer > >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { + pl->p_peers.push_back(ZT_Peer()); + ZT_Peer &p = pl->p_peers.back(); + Peer &pp = **pi; - const int64_t now = m_now; + p.address = pp.address(); + pl->p_identities.push_back(pp.identity()); + p.identity = reinterpret_cast(&(pl->p_identities.back())); + p.fingerprint = &(pl->p_identities.back().fingerprint()); + if (pp.remoteVersionKnown()) { + p.versionMajor = (int)pp.remoteVersionMajor(); + p.versionMinor = (int)pp.remoteVersionMinor(); + p.versionRev = (int)pp.remoteVersionRevision(); + p.versionProto = (int)pp.remoteVersionProtocol(); + } else { + p.versionMajor = -1; + p.versionMinor = -1; + p.versionRev = -1; + p.versionProto = -1; + } + p.latency = pp.latency(); + p.root = std::binary_search(rootPeers.begin(), rootPeers.end(), *pi) ? 1 : 0; - pl->peerCount = 0; - for (Vector< SharedPtr< Peer > >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { - ZT_Peer *const p = pl->peers + pl->peerCount; + p.networks = nullptr; + p.networkCount = 0; // TODO: networks this peer belongs to - p->address = (*pi)->address().toInt(); - identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted - p->identity = identities + pl->peerCount; - p->fingerprint.address = p->address; - Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(p->fingerprint.hash, (*pi)->identity().fingerprint().hash); - if ((*pi)->remoteVersionKnown()) { - p->versionMajor = (int)(*pi)->remoteVersionMajor(); - p->versionMinor = (int)(*pi)->remoteVersionMinor(); - p->versionRev = (int)(*pi)->remoteVersionRevision(); - } else { - p->versionMajor = -1; - p->versionMinor = -1; - p->versionRev = -1; - } - p->latency = (*pi)->latency(); - p->root = (std::find(rootPeers.begin(), rootPeers.end(), *pi) != rootPeers.end()) ? 1 : 0; + Vector< SharedPtr > ztPaths; + pp.getAllPaths(ztPaths); + if (ztPaths.empty()) { + pl->p_paths.push_back(std::vector< ZT_Path >()); + std::vector< ZT_Path > &apiPaths = pl->p_paths.back(); + apiPaths.resize(ztPaths.size()); + for (unsigned long i = 0; i < (unsigned long)ztPaths.size(); ++i) { + SharedPtr< Path > &ztp = ztPaths[i]; + ZT_Path &apip = apiPaths[i]; + apip.endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; + Utils::copy< sizeof(struct sockaddr_storage) >(&(apip.endpoint.value.ss), &(ztp->address().as.ss)); + apip.lastSend = ztp->lastOut(); + apip.lastReceive = ztp->lastIn(); + apip.alive = ztp->alive(now) ? 1 : 0; + apip.preferred = (i == 0) ? 1 : 0; + } + p.paths = apiPaths.data(); + p.pathCount = (unsigned int)apiPaths.size(); + } else { + p.paths = nullptr; + p.pathCount = 0; + } - p->networkCount = 0; - // TODO: enumerate network memberships - - Vector< SharedPtr< Path > > paths; - (*pi)->getAllPaths(paths); - p->pathCount = (unsigned int)paths.size(); - p->paths = peerPath; - for (Vector< SharedPtr< Path > >::iterator path(paths.begin()); path != paths.end(); ++path) { - ZT_Path *const pp = peerPath++; - pp->endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; // only type supported right now - Utils::copy< sizeof(sockaddr_storage) >(&pp->endpoint.value.ss, &((*path)->address().as.ss)); - pp->lastSend = (*path)->lastOut(); - pp->lastReceive = (*path)->lastIn(); - pp->alive = (*path)->alive(now) ? 1 : 0; - pp->preferred = (p->pathCount == 0) ? 1 : 0; - } - - const SharedPtr< const Locator > loc((*pi)->locator()); - if (loc) { - const int ls = loc->marshal(locatorBuf); - if (ls > 0) { - p->locatorSize = (unsigned int)ls; - p->locator = locatorBuf; - locatorBuf += ls; + const SharedPtr< const Locator > loc(pp.locator()); + if (loc) { + pl->p_locators.push_back(Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX >()); + Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX > &lb = pl->p_locators.back(); + Utils::zero< ZT_LOCATOR_MARSHAL_SIZE_MAX >(lb.data); + const int ls = loc->marshal(lb.data); + if (ls > 0) { + p.locatorSize = (unsigned int)ls; + p.locator = lb.data; + } } } - ++pl->peerCount; - } + pl->peers = pl->p_peers.data(); + pl->peerCount = (unsigned long)pl->p_peers.size(); - return pl; + return pl; + } catch ( ... ) { + delete pl; + return nullptr; + } } ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const @@ -482,7 +496,7 @@ ZT_VirtualNetworkList *Node::networks() const char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_networks.size())); if (!buf) return nullptr; - ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; // NOLINT(modernize-use-auto,hicpp-use-auto) + ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; nl->freeFunction = reinterpret_cast(free); nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); diff --git a/core/zerotier.h b/core/zerotier.h index 1b21be135..9030f2906 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -1578,7 +1578,7 @@ typedef struct /** * SHA-384 of identity public key(s) */ - ZT_Fingerprint fingerprint; + const ZT_Fingerprint *fingerprint; /** * Remote major version or -1 if not known @@ -1595,6 +1595,11 @@ typedef struct */ int versionRev; + /** + * Remote protocol version or -1 if not known + */ + int versionProto; + /** * Last measured latency in milliseconds or -1 if unknown */ @@ -1605,20 +1610,15 @@ typedef struct */ int root; - /** - * Number of networks in which this peer is authenticated - */ - unsigned int networkCount; - /** * Network IDs for networks (array size: networkCount) */ uint64_t *networks; /** - * Number of paths (size of paths[]) + * Number of networks in which this peer is authenticated */ - unsigned int pathCount; + unsigned int networkCount; /** * Known network paths to peer (array size: pathCount). @@ -1629,6 +1629,11 @@ typedef struct */ ZT_Path *paths; + /** + * Number of paths (size of paths[]) + */ + unsigned int pathCount; + /** * Size of locator in bytes or 0 if none */ diff --git a/pkg/zerotier/peer.go b/pkg/zerotier/peer.go index 788fe5b89..36077d6dd 100644 --- a/pkg/zerotier/peer.go +++ b/pkg/zerotier/peer.go @@ -37,7 +37,7 @@ func newPeerFromCPeer(cp *C.ZT_Peer) (p *Peer, err error) { if err != nil { return } - p.Fingerprint = newFingerprintFromCFingerprint(&(cp.fingerprint)) + p.Fingerprint = newFingerprintFromCFingerprint(cp.fingerprint) p.Version[0] = int(cp.versionMajor) p.Version[1] = int(cp.versionMinor) p.Version[2] = int(cp.versionRev)