mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-19 21:46:54 +02:00
A bunch of go fixes, wire up root add/delete.
This commit is contained in:
parent
964c235ecf
commit
caad356b93
11 changed files with 134 additions and 89 deletions
|
@ -92,7 +92,7 @@ struct ZT_GoNode_Impl
|
|||
};
|
||||
|
||||
static const std::string defaultHomePath(OSUtils::platformDefaultHomePath());
|
||||
const char *ZT_PLATFORM_DEFAULT_HOMEPATH = defaultHomePath.c_str();
|
||||
const char *const ZT_PLATFORM_DEFAULT_HOMEPATH = defaultHomePath.c_str();
|
||||
|
||||
// These are implemented in Go code.
|
||||
extern "C" int goPathCheckFunc(void *,const ZT_Identity *,int,const void *,int);
|
||||
|
@ -300,6 +300,7 @@ extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr)
|
|||
{
|
||||
try {
|
||||
struct ZT_Node_Callbacks cb;
|
||||
|
||||
cb.statePutFunction = &ZT_GoNode_StatePutFunction;
|
||||
cb.stateGetFunction = &ZT_GoNode_StateGetFunction;
|
||||
cb.wirePacketSendFunction = &ZT_GoNode_WirePacketSendFunction;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../include/ZeroTierCore.h"
|
||||
#include "../../node/Constants.hpp"
|
||||
|
@ -29,7 +30,7 @@ typedef void ZT_GoTap;
|
|||
struct ZT_GoNode_Impl;
|
||||
typedef struct ZT_GoNode_Impl ZT_GoNode;
|
||||
|
||||
extern const char *ZT_PLATFORM_DEFAULT_HOMEPATH;
|
||||
extern const char *const ZT_PLATFORM_DEFAULT_HOMEPATH;
|
||||
|
||||
ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr);
|
||||
void ZT_GoNode_delete(ZT_GoNode *gn);
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
secrand "crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -33,8 +34,6 @@ import (
|
|||
// APISocketName is the default socket name for accessing the API
|
||||
const APISocketName = "apisocket"
|
||||
|
||||
var startTime = TimeMs()
|
||||
|
||||
// APIGet makes a query to the API via a Unix domain or windows pipe socket
|
||||
func APIGet(basePath, socketName, authToken, queryPath string, obj interface{}) (int, int64, error) {
|
||||
client, err := createNamedSocketHTTPClient(basePath, socketName)
|
||||
|
@ -128,7 +127,7 @@ type APIStatus struct {
|
|||
Address Address `json:"address"`
|
||||
Clock int64 `json:"clock"`
|
||||
StartupTime int64 `json:"startupTime"`
|
||||
Config LocalConfig `json:"config"`
|
||||
Config *LocalConfig `json:"config"`
|
||||
Online bool `json:"online"`
|
||||
PeerCount int `json:"peerCount"`
|
||||
PathCount int `json:"pathCount"`
|
||||
|
@ -254,8 +253,6 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
|
||||
smux := http.NewServeMux()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
|
@ -278,7 +275,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
_ = apiSendObj(out, req, http.StatusOK, &APIStatus{
|
||||
Address: node.Address(),
|
||||
Clock: TimeMs(),
|
||||
StartupTime: startTime,
|
||||
StartupTime: node.startupTime,
|
||||
Config: node.LocalConfig(),
|
||||
Online: node.Online(),
|
||||
PeerCount: len(peers),
|
||||
|
@ -302,8 +299,6 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
|
@ -336,9 +331,9 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
|
@ -351,65 +346,92 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
}
|
||||
apiSetStandardHeaders(out)
|
||||
|
||||
if req.URL.Path == "/peer/_addroot" {
|
||||
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
rsdata, err := ioutil.ReadAll(io.LimitReader(req.Body, 16384))
|
||||
if err != nil || len(rsdata) == 0 {
|
||||
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"read error"})
|
||||
} else {
|
||||
p, err := node.AddRoot(rsdata)
|
||||
if err != nil {
|
||||
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"invalid root spec"})
|
||||
}
|
||||
_ = apiSendObj(out, req, http.StatusOK, p)
|
||||
}
|
||||
} else {
|
||||
out.Header().Set("Allow", "POST, PUT")
|
||||
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"no root spec supplied"})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var queriedStr string
|
||||
var queriedID Address
|
||||
var queriedFP *Fingerprint
|
||||
if len(req.URL.Path) > 6 {
|
||||
var err error
|
||||
queriedID, err = NewAddressFromString(req.URL.Path[6:])
|
||||
if err != nil {
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
return
|
||||
queriedStr = req.URL.Path[6:]
|
||||
if len(queriedStr) == AddressStringLength {
|
||||
queriedID, err = NewAddressFromString(queriedStr)
|
||||
if err != nil {
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
queriedFP, err = NewFingerprintFromString(queriedStr)
|
||||
if err != nil {
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Right now POST/PUT is only used with peers to add or remove root servers.
|
||||
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
if queriedID == 0 {
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
return
|
||||
var peer *Peer
|
||||
peers := node.Peers()
|
||||
if queriedFP != nil {
|
||||
for _, p := range peers {
|
||||
if p.Fingerprint.Equals(queriedFP) {
|
||||
peer = p
|
||||
break
|
||||
}
|
||||
}
|
||||
var peerChanges PeerMutableFields
|
||||
if apiReadObj(out, req, &peerChanges) == nil {
|
||||
if peerChanges.Root != nil || peerChanges.Bootstrap != nil {
|
||||
peers := node.Peers()
|
||||
for _, p := range peers {
|
||||
if p.Address == queriedID && (peerChanges.Identity == nil || peerChanges.Identity.Equals(p.Identity)) {
|
||||
if peerChanges.Root != nil && *peerChanges.Root != p.Root {
|
||||
if *peerChanges.Root {
|
||||
_ = node.AddRoot(p.Identity, peerChanges.Bootstrap)
|
||||
} else {
|
||||
node.RemoveRoot(p.Identity)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
} else if queriedID != 0 {
|
||||
for _, p := range peers {
|
||||
if p.Address == queriedID {
|
||||
peer = p
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
if peer != nil {
|
||||
var posted Peer
|
||||
if apiReadObj(out, req, &posted) == nil {
|
||||
if posted.Root && !peer.Root {
|
||||
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"root spec must be submitted to /peer/_addroot, post to peers can only be used to clear the root flag"})
|
||||
} else if !posted.Root && peer.Root {
|
||||
peer.Root = false
|
||||
node.RemoveRoot(peer.Address)
|
||||
_ = apiSendObj(out, req, http.StatusOK, peer)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
}
|
||||
}
|
||||
|
||||
if req.Method == http.MethodGet || req.Method == http.MethodHead || req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
peers := node.Peers()
|
||||
if queriedID != 0 {
|
||||
for _, p := range peers {
|
||||
if p.Address == queriedID {
|
||||
_ = apiSendObj(out, req, http.StatusOK, p)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if req.Method == http.MethodGet || req.Method == http.MethodHead || req.Method == http.MethodPost || req.Method == http.MethodPut {
|
||||
if peer != nil {
|
||||
_ = apiSendObj(out, req, http.StatusOK, peer)
|
||||
} else if len(queriedStr) > 0 {
|
||||
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
|
||||
} else {
|
||||
_ = apiSendObj(out, req, http.StatusOK, peers)
|
||||
}
|
||||
} else {
|
||||
out.Header().Set("Allow", "GET, HEAD, PUT, POST")
|
||||
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"peers are read only"})
|
||||
out.Header().Set("Allow", "GET, HEAD, POST, PUT")
|
||||
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"unsupported method"})
|
||||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
|
@ -496,8 +518,6 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
|||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
listener, err := createNamedSocketListener(basePath, APISocketName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
|
@ -18,6 +18,7 @@ package zerotier
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
@ -49,6 +50,10 @@ func (fp *Fingerprint) String() string {
|
|||
return Base32StdLowerCase.EncodeToString(tmp[:])
|
||||
}
|
||||
|
||||
func (fp *Fingerprint) Equals(fp2 *Fingerprint) bool {
|
||||
return fp.Address == fp2.Address && bytes.Equal(fp.Hash[:], fp2.Hash[:])
|
||||
}
|
||||
|
||||
func (fp *Fingerprint) apiFingerprint() *C.ZT_Fingerprint {
|
||||
var apifp C.ZT_Fingerprint
|
||||
apifp.address = C.uint64_t(fp.Address)
|
||||
|
|
|
@ -27,14 +27,15 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// Constants from node/Identity.hpp (must be the same)
|
||||
const (
|
||||
IdentityTypeC25519 = C.ZT_IDENTITY_TYPE_C25519
|
||||
IdentityTypeP384 = C.ZT_IDENTITY_TYPE_P384
|
||||
IdentityTypeC25519 = 0
|
||||
IdentityTypeP384 = 1
|
||||
|
||||
IdentityTypeC25519PublicKeySize = C.ZT_IDENTITY_C25519_PUBLIC_KEY_SIZE
|
||||
IdentityTypeC25519PrivateKeySize = C.ZT_IDENTITY_C25519_PRIVATE_KEY_SIZE
|
||||
IdentityTypeP384PublicKeySize = C.ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE
|
||||
IdentityTypeP384PrivateKeySize = C.ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE
|
||||
IdentityTypeC25519PublicKeySize = 64
|
||||
IdentityTypeC25519PrivateKeySize = 64
|
||||
IdentityTypeP384PublicKeySize = 114
|
||||
IdentityTypeP384PrivateKeySize = 112
|
||||
)
|
||||
|
||||
// Identity is precisely what it sounds like: the address and associated keys for a ZeroTier node
|
||||
|
@ -239,14 +240,14 @@ func (id *Identity) MakeRoot(addresses []InetAddress) ([]byte, error) {
|
|||
return nil, errors.New("error initializing ZT_Identity")
|
||||
}
|
||||
|
||||
ss := make([]C.sockaddr_storage, len(addresses))
|
||||
ss := make([]C.struct_sockaddr_storage, len(addresses))
|
||||
for i := range addresses {
|
||||
if !makeSockaddrStorage(addresses[i].IP, addresses[i].Port, &ss[i]) {
|
||||
return nil, errors.New("invalid address in address list")
|
||||
}
|
||||
}
|
||||
var buf [8192]byte
|
||||
rl := C.ZT_Identity_makeRootSpecification(id.cid, C.int64_t(TimeMs()), &ss[0], C.uint(len(ss)), &buf[0], 8192)
|
||||
rl := C.ZT_Identity_makeRootSpecification(id.cid, C.int64_t(TimeMs()), &ss[0], C.uint(len(ss)), unsafe.Pointer(&buf[0]), 8192)
|
||||
if rl <= 0 {
|
||||
return nil, errors.New("unable to make root specification (does identity contain a secret key?)")
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ const (
|
|||
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
|
||||
|
||||
// maxCNodeRefs is the maximum number of Node instances that can be created in this process (increasing is fine)
|
||||
maxCNodeRefs = 4
|
||||
maxCNodeRefs = 8
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -90,6 +90,9 @@ func init() {
|
|||
|
||||
// Node is an instance of a virtual port on the global switch.
|
||||
type Node struct {
|
||||
// Time this node was created
|
||||
startupTime int64
|
||||
|
||||
// an arbitrary uintptr given to the core as its pointer back to Go's Node instance
|
||||
cPtr uintptr
|
||||
|
||||
|
@ -146,13 +149,14 @@ type Node struct {
|
|||
// NewNode creates and initializes a new instance of the ZeroTier node service
|
||||
func NewNode(basePath string) (n *Node, err error) {
|
||||
n = new(Node)
|
||||
n.startupTime = TimeMs()
|
||||
|
||||
// Register this with the cNodeRefs lookup array and set up a deferred function
|
||||
// to unregister this if we exit before the end of the constructor such as by
|
||||
// returning an error.
|
||||
cPtr := -1
|
||||
for i:=0;i<maxCNodeRefs;i++ {
|
||||
if atomic.CompareAndSwapUint32(&cNodeRefUsed[i],0,1) {
|
||||
for i := 0; i < maxCNodeRefs; i++ {
|
||||
if atomic.CompareAndSwapUint32(&cNodeRefUsed[i], 0, 1) {
|
||||
cNodeRefs[i] = n
|
||||
cPtr = i
|
||||
n.cPtr = uintptr(i)
|
||||
|
@ -164,7 +168,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
|||
}
|
||||
defer func() {
|
||||
if cPtr >= 0 {
|
||||
atomic.StoreUint32(&cNodeRefUsed[cPtr],0)
|
||||
atomic.StoreUint32(&cNodeRefUsed[cPtr], 0)
|
||||
cNodeRefs[cPtr] = nil
|
||||
}
|
||||
}()
|
||||
|
@ -331,7 +335,7 @@ func (n *Node) Close() {
|
|||
n.runWaitGroup.Wait()
|
||||
|
||||
cNodeRefs[n.cPtr] = nil
|
||||
atomic.StoreUint32(&cNodeRefUsed[n.cPtr],0)
|
||||
atomic.StoreUint32(&cNodeRefUsed[n.cPtr], 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,11 +449,31 @@ func (n *Node) Leave(nwid NetworkID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) AddRoot(spec []byte) error {
|
||||
return nil
|
||||
func (n *Node) AddRoot(spec []byte) (*Peer, error) {
|
||||
if len(spec) == 0 {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
var address C.uint64_t
|
||||
res := C.ZT_Node_addRoot(n.zn, nil, unsafe.Pointer(&spec[0]), C.uint(len(spec)), &address)
|
||||
if res != 0 {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
peers := n.Peers()
|
||||
for _, p := range peers {
|
||||
if p.Address == Address(uint64(address)) {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrInternal
|
||||
}
|
||||
|
||||
func (n *Node) RemoveRoot(address Address) {
|
||||
var cfp C.ZT_Fingerprint
|
||||
cfp.address = C.uint64_t(address)
|
||||
for i := 0; i < 48; i++ {
|
||||
cfp.hash[i] = 0
|
||||
}
|
||||
C.ZT_Node_removeRoot(n.zn, nil, &cfp)
|
||||
}
|
||||
|
||||
// GetNetwork looks up a network by ID or returns nil if not joined
|
||||
|
@ -481,7 +505,8 @@ func (n *Node) Peers() []*Peer {
|
|||
p2 := new(Peer)
|
||||
p2.Address = Address(p.address)
|
||||
p2.Identity, _ = newIdentityFromCIdentity(unsafe.Pointer(p.identity))
|
||||
p2.Fingerprint = C.GoBytes(unsafe.Pointer(&p.fingerprint.hash[0]), 48)
|
||||
p2.Fingerprint.Address = p2.Address
|
||||
copy(p2.Fingerprint.Hash[:], ((*[48]byte)(unsafe.Pointer(&p.fingerprint.hash[0])))[:])
|
||||
p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
|
||||
p2.Latency = int(p.latency)
|
||||
p2.Root = p.root != 0
|
||||
|
@ -498,7 +523,6 @@ func (n *Node) Peers() []*Peer {
|
|||
Port: a.Port,
|
||||
LastSend: int64(pt.lastSend),
|
||||
LastReceive: int64(pt.lastReceive),
|
||||
TrustedPathID: uint64(pt.trustedPathId),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -602,7 +626,7 @@ func (n *Node) runMaintenance() {
|
|||
}
|
||||
for _, ip := range interfaceAddresses {
|
||||
for _, p := range ports {
|
||||
a := InetAddress{ IP: ip, Port: p }
|
||||
a := InetAddress{IP: ip, Port: p}
|
||||
ak := a.key()
|
||||
if _, have := externalAddresses[ak]; !have {
|
||||
externalAddresses[ak] = &a
|
||||
|
|
|
@ -21,5 +21,4 @@ type Path struct {
|
|||
Port int `json:"port"`
|
||||
LastSend int64 `json:"lastSend"`
|
||||
LastReceive int64 `json:"lastReceive"`
|
||||
TrustedPathID uint64 `json:"trustedPathID"`
|
||||
}
|
||||
|
|
|
@ -17,16 +17,10 @@ package zerotier
|
|||
type Peer struct {
|
||||
Address Address `json:"address"`
|
||||
Identity *Identity `json:"identity"`
|
||||
Fingerprint []byte `json:"fingerprint"`
|
||||
Fingerprint Fingerprint `json:"fingerprint"`
|
||||
Version [3]int `json:"version"`
|
||||
Latency int `json:"latency"`
|
||||
Root bool `json:"root"`
|
||||
Bootstrap *InetAddress `json:"bootstrap,omitempty"`
|
||||
Paths []Path `json:"paths,omitempty"`
|
||||
}
|
||||
|
||||
// PeerMutableFields contains only the mutable fields of Peer as nullable pointers.
|
||||
type PeerMutableFields struct {
|
||||
Root *bool `json:"root"`
|
||||
RootSpec []byte `json:"rootSpec"`
|
||||
}
|
||||
|
|
|
@ -1755,9 +1755,10 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_
|
|||
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
|
||||
* @param rdef Root definition (serialized identity and locator)
|
||||
* @param rdeflen Length of root definition in bytes
|
||||
* @param address If non-NULL will be filled with the ZeroTier address of the root (only defined if return is OK)
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen);
|
||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address);
|
||||
|
||||
/**
|
||||
* Remove a root
|
||||
|
|
|
@ -224,9 +224,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
|
|||
|
||||
if (pf.online) {
|
||||
// If we have at least one online root, request whois for roots not online.
|
||||
// This will give us updated locators for these roots which may contain new
|
||||
// IP addresses. It will also auto-discover IPs for roots that were not added
|
||||
// with an initial bootstrap address.
|
||||
// TODO
|
||||
//for (Vector<Address>::const_iterator r(pf.rootsNotOnline.begin()); r != pf.rootsNotOnline.end(); ++r)
|
||||
// RR->sw->requestWhois(tPtr,now,*r);
|
||||
|
@ -339,11 +336,13 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
|
|||
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::addRoot(void *tPtr,const void *rdef,unsigned int rdeflen)
|
||||
ZT_ResultCode Node::addRoot(void *tPtr,const void *rdef,unsigned int rdeflen,uint64_t *address)
|
||||
{
|
||||
if ((!rdef)||(rdeflen == 0))
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
std::pair<Identity,Locator> r(Locator::parseRootSpecification(rdef,rdeflen));
|
||||
if (address)
|
||||
*address = r.first.address().toInt();
|
||||
return ((r.first)&&(RR->topology->addRoot(tPtr,r.first,r.second))) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -862,10 +861,10 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint
|
|||
}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen)
|
||||
enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address)
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(tptr,rdef,rdeflen);
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(tptr,rdef,rdeflen,address);
|
||||
} catch (std::bad_alloc &exc) {
|
||||
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
|
||||
} catch ( ... ) {
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
|
||||
ZT_ResultCode multicastSubscribe(void *tPtr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
|
||||
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
|
||||
ZT_ResultCode addRoot(void *tptr,const void *rdef,unsigned int rdeflen);
|
||||
ZT_ResultCode addRoot(void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address);
|
||||
ZT_ResultCode removeRoot(void *tptr,const ZT_Fingerprint *fp);
|
||||
uint64_t address() const;
|
||||
void status(ZT_NodeStatus *status) const;
|
||||
|
|
Loading…
Add table
Reference in a new issue