mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
New service, work in progress
This commit is contained in:
parent
3ceb2257e5
commit
ae2120eb96
15 changed files with 852 additions and 18 deletions
|
@ -141,7 +141,7 @@ endif()
|
||||||
add_subdirectory(node)
|
add_subdirectory(node)
|
||||||
add_subdirectory(controller)
|
add_subdirectory(controller)
|
||||||
add_subdirectory(osdep)
|
add_subdirectory(osdep)
|
||||||
add_subdirectory(service)
|
#add_subdirectory(service)
|
||||||
add_subdirectory(root)
|
add_subdirectory(root)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -151,7 +151,7 @@ if(WIN32)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
set(libs
|
set(libs
|
||||||
zt_service
|
# zt_service
|
||||||
zt_osdep
|
zt_osdep
|
||||||
zt_core
|
zt_core
|
||||||
zt_controller
|
zt_controller
|
||||||
|
|
30
attic/listaddrinfo.go
Normal file
30
attic/listaddrinfo.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ifs, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, i := range ifs {
|
||||||
|
fmt.Printf("name: %s\n", i.Name)
|
||||||
|
fmt.Printf("hwaddr: %s\n", i.HardwareAddr.String())
|
||||||
|
fmt.Printf("index: %d\n", i.Index)
|
||||||
|
fmt.Printf("addrs:\n")
|
||||||
|
addrs, _ := i.Addrs()
|
||||||
|
for _, a := range addrs {
|
||||||
|
fmt.Printf(" %s\n", a.String())
|
||||||
|
}
|
||||||
|
fmt.Printf("multicast:\n")
|
||||||
|
mc, _ := i.MulticastAddrs()
|
||||||
|
for _, m := range mc {
|
||||||
|
fmt.Printf(" %s\n", m.String())
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
3
go/go.mod
Normal file
3
go/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module zerotier-go
|
||||||
|
|
||||||
|
go 1.13
|
13
go/native/CMakeLists.txt
Normal file
13
go/native/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(zt_go_native)
|
||||||
|
|
||||||
|
set(src
|
||||||
|
GoNode.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(headers
|
||||||
|
GoNode.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${src} ${headers})
|
||||||
|
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
|
493
go/native/GoNode.cpp
Normal file
493
go/native/GoNode.cpp
Normal file
|
@ -0,0 +1,493 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2019 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2023-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by vergnn 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#include "GoNode.h"
|
||||||
|
|
||||||
|
#include "../../node/Constants.hpp"
|
||||||
|
#include "../../node/InetAddress.hpp"
|
||||||
|
#include "../../node/Node.hpp"
|
||||||
|
#include "../../node/Utils.hpp"
|
||||||
|
#include "../../osdep/OSUtils.hpp"
|
||||||
|
#include "../../osdep/BlockingQueue.hpp"
|
||||||
|
#include "../../osdep/EthernetTap.hpp"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef __WINDOWS__
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#ifdef __BSD__
|
||||||
|
#include <net/if.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __LINUX__
|
||||||
|
#ifndef IPV6_DONTFRAG
|
||||||
|
#define IPV6_DONTFRAG 62
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif // !__WINDOWS__
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
#define SETSOCKOPT_FLAG_TYPE BOOL
|
||||||
|
#define SETSOCKOPT_FLAG_TRUE TRUE
|
||||||
|
#define SETSOCKOPT_FLAG_FALSE FALSE
|
||||||
|
#else
|
||||||
|
#define SETSOCKOPT_FLAG_TYPE int
|
||||||
|
#define SETSOCKOPT_FLAG_TRUE 1
|
||||||
|
#define SETSOCKOPT_FLAG_FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MSG_DONTWAIT
|
||||||
|
#define MSG_DONTWAIT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace ZeroTier;
|
||||||
|
|
||||||
|
struct ZT_GoNodeThread
|
||||||
|
{
|
||||||
|
std::string ip;
|
||||||
|
int port;
|
||||||
|
int af;
|
||||||
|
std::atomic_bool run;
|
||||||
|
std::thread thr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZT_GoNode_Impl
|
||||||
|
{
|
||||||
|
Node *node;
|
||||||
|
volatile int64_t nextBackgroundTaskDeadline;
|
||||||
|
|
||||||
|
int (*goPathCheckFunc)(ZT_GoNode *,ZT_Node *,uint64_t ztAddress,const void *);
|
||||||
|
int (*goPathLookupFunc)(ZT_GoNode *,ZT_Node *,int desiredAddressFamily,void *);
|
||||||
|
int (*goStateObjectGetFunc)(ZT_GoNode *,ZT_Node *,int objType,const uint64_t id[2],void *buf,unsigned int bufSize);
|
||||||
|
|
||||||
|
std::map< ZT_SOCKET,ZT_GoNodeThread > threads;
|
||||||
|
std::mutex threads_l;
|
||||||
|
|
||||||
|
BlockingQueue<ZT_GoNodeEvent> eq;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static int ZT_GoNode_VirtualNetworkConfigFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
uint64_t nwid,
|
||||||
|
void **nptr,
|
||||||
|
enum ZT_VirtualNetworkConfigOperation op,
|
||||||
|
const ZT_VirtualNetworkConfig *cfg)
|
||||||
|
{
|
||||||
|
ZT_GoNodeEvent ev;
|
||||||
|
ev.type = ZT_GONODE_EVENT_NETWORK_CONFIG_UPDATE;
|
||||||
|
ev.data.nconf.op = op;
|
||||||
|
if (cfg)
|
||||||
|
ev.data.nconf.conf = *cfg;
|
||||||
|
reinterpret_cast<ZT_GoNode *>(uptr)->eq.post(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZT_GoNode_VirtualNetworkFrameFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
uint64_t nwid,
|
||||||
|
void **nptr,
|
||||||
|
uint64_t srcMac,
|
||||||
|
uint64_t destMac,
|
||||||
|
unsigned int etherType,
|
||||||
|
unsigned int vlanId,
|
||||||
|
const void *data,
|
||||||
|
unsigned int len)
|
||||||
|
{
|
||||||
|
if (*nptr)
|
||||||
|
reinterpret_cast<EthernetTap *>(*nptr)->put(MAC(srcMac),MAC(destMac),etherType,data,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZT_GoNode_EventCallback(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
enum ZT_Event et,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
ZT_GoNodeEvent ev;
|
||||||
|
ev.type = ZT_GONODE_EVENT_ZTEVENT;
|
||||||
|
ev.data.zt.type = et;
|
||||||
|
reinterpret_cast<ZT_GoNode *>(uptr)->eq.post(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZT_GoNode_StatePutFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
enum ZT_StateObjectType objType,
|
||||||
|
const uint64_t id[2],
|
||||||
|
const void *data,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
if (len < ZT_MAX_STATE_OBJECT_SIZE) { // sanity check
|
||||||
|
ZT_GoNodeEvent ev;
|
||||||
|
ev.type = (len >= 0) ? ZT_GONODE_EVENT_STATE_PUT : ZT_GONODE_EVENT_STATE_DELETE;
|
||||||
|
if (len > 0) {
|
||||||
|
memcpy(ev.data.sobj.data,data,len);
|
||||||
|
ev.data.sobj.len = (unsigned int)len;
|
||||||
|
}
|
||||||
|
ev.data.sobj.objType = objType;
|
||||||
|
ev.data.sobj.id[0] = id[0];
|
||||||
|
ev.data.sobj.id[1] = id[1];
|
||||||
|
reinterpret_cast<ZT_GoNode *>(uptr)->eq.post(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ZT_GoNode_StateGetFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
enum ZT_StateObjectType objType,
|
||||||
|
const uint64_t id[2],
|
||||||
|
void *buf,
|
||||||
|
unsigned int buflen)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ZT_GoNode *>(uptr)->goStateObjectGetFunc(reinterpret_cast<ZT_GoNode *>(uptr),reinterpret_cast<ZT_GoNode *>(uptr)->node,(int)objType,id,buf,buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZT_ALWAYS_INLINE void doUdpSend(ZT_SOCKET sock,const struct sockaddr_storage *addr,const void *data,const unsigned int len,const unsigned int ipTTL)
|
||||||
|
{
|
||||||
|
switch(addr->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
if ((ipTTL > 0)&&(ipTTL < 255)) {
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
DWORD tmp = (DWORD)ipTTL;
|
||||||
|
#else
|
||||||
|
int tmp = (int)ipTTL;
|
||||||
|
#endif
|
||||||
|
setsockopt(sock,IPPROTO_IP,IP_TTL,&tmp,sizeof(tmp));
|
||||||
|
sendto(sock,data,len,MSG_DONTWAIT,(const sockaddr *)addr,sizeof(struct sockaddr_in));
|
||||||
|
tmp = 255;
|
||||||
|
setsockopt(sock,IPPROTO_IP,IP_TTL,&tmp,sizeof(tmp));
|
||||||
|
} else {
|
||||||
|
sendto(sock,data,len,MSG_DONTWAIT,(const sockaddr *)addr,sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
// The ipTTL option isn't currently used with IPv6. It's only used
|
||||||
|
// with IPv4 "firewall opener" / "NAT buster" preamble packets as part
|
||||||
|
// of IPv4 NAT traversal.
|
||||||
|
sendto(sock,data,len,MSG_DONTWAIT,(const sockaddr *)addr,sizeof(struct sockaddr_in6));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZT_GoNode_WirePacketSendFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
int64_t localSocket,
|
||||||
|
const struct sockaddr_storage *addr,
|
||||||
|
const void *data,
|
||||||
|
unsigned int len,
|
||||||
|
unsigned int ipTTL)
|
||||||
|
{
|
||||||
|
if ((localSocket != -1)&&(localSocket != ZT_INVALID_SOCKET)) {
|
||||||
|
doUdpSend((ZT_SOCKET)localSocket,addr,data,len,ipTTL);
|
||||||
|
} else {
|
||||||
|
ZT_GoNode *const gn = reinterpret_cast<ZT_GoNode *>(uptr);
|
||||||
|
std::set<std::string> ipsSentFrom;
|
||||||
|
std::lock_guard<std::mutex> l(gn->threads_l);
|
||||||
|
for(auto t=gn->threads.begin();t!=gn->threads.end();++t) {
|
||||||
|
if (t->second.af == addr->ss_family) {
|
||||||
|
if (ipsSentFrom.insert(t->second.ip).second) {
|
||||||
|
doUdpSend(t->first,addr,data,len,ipTTL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ZT_GoNode_PathCheckFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
uint64_t ztAddress,
|
||||||
|
int64_t localSocket,
|
||||||
|
const struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ZT_GoNode *>(uptr)->goPathCheckFunc(reinterpret_cast<ZT_GoNode *>(uptr),reinterpret_cast<ZT_GoNode *>(uptr)->node,ztAddress,sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ZT_GoNode_PathLookupFunction(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
uint64_t ztAddress,
|
||||||
|
int desiredAddressFamily,
|
||||||
|
struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ZT_GoNode *>(uptr)->goPathLookupFunc(reinterpret_cast<ZT_GoNode *>(uptr),reinterpret_cast<ZT_GoNode *>(uptr)->node,desiredAddressFamily,sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZT_GoNode_DNSResolver(
|
||||||
|
ZT_Node *node,
|
||||||
|
void *uptr,
|
||||||
|
void *tptr,
|
||||||
|
const enum ZT_DNSRecordType *types,
|
||||||
|
unsigned int numTypes,
|
||||||
|
const char *name,
|
||||||
|
uintptr_t requestId)
|
||||||
|
{
|
||||||
|
ZT_GoNodeEvent ev;
|
||||||
|
ev.type = ZT_GONODE_EVENT_DNS_GET_TXT;
|
||||||
|
Utils::scopy(ev.data.dns.dnsName,sizeof(ev.data.dns.dnsName),name);
|
||||||
|
reinterpret_cast<ZT_GoNode *>(uptr)->eq.post(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern "C" ZT_GoNode *ZT_GoNode_new(
|
||||||
|
int (*goPathCheckFunc)(ZT_GoNode *,ZT_Node *,uint64_t ztAddress,const void *),
|
||||||
|
int (*goPathLookupFunc)(ZT_GoNode *,ZT_Node *,int desiredAddressFamily,void *),
|
||||||
|
int (*goStateObjectGetFunc)(ZT_GoNode *,ZT_Node *,int objType,const uint64_t id[2],void *buf,unsigned int bufSize)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
struct ZT_Node_Callbacks cb;
|
||||||
|
cb.virtualNetworkConfigFunction = &ZT_GoNode_VirtualNetworkConfigFunction;
|
||||||
|
cb.virtualNetworkFrameFunction = &ZT_GoNode_VirtualNetworkFrameFunction;
|
||||||
|
cb.eventCallback = &ZT_GoNode_EventCallback;
|
||||||
|
cb.statePutFunction = &ZT_GoNode_StatePutFunction;
|
||||||
|
cb.stateGetFunction = &ZT_GoNode_StateGetFunction;
|
||||||
|
cb.pathCheckFunction = &ZT_GoNode_PathCheckFunction;
|
||||||
|
cb.pathLookupFunction = &ZT_GoNode_PathLookupFunction;
|
||||||
|
cb.dnsResolver = &ZT_GoNode_DNSResolver;
|
||||||
|
|
||||||
|
ZT_GoNode_Impl *gn = new ZT_GoNode_Impl;
|
||||||
|
const int64_t now = OSUtils::now();
|
||||||
|
gn->node = new Node(reinterpret_cast<void *>(gn),nullptr,&cb,now);
|
||||||
|
gn->nextBackgroundTaskDeadline = now;
|
||||||
|
gn->goPathCheckFunc = goPathCheckFunc;
|
||||||
|
gn->goPathLookupFunc = goPathLookupFunc;
|
||||||
|
gn->goStateObjectGetFunc = goStateObjectGetFunc;
|
||||||
|
return gn;
|
||||||
|
} catch ( ... ) {
|
||||||
|
fprintf(stderr,"FATAL: unable to create new instance of Node (out of memory?)" ZT_EOL_S);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void ZT_GoNode_delete(ZT_GoNode *gn)
|
||||||
|
{
|
||||||
|
ZT_GoNodeEvent sd;
|
||||||
|
sd.type = ZT_GONODE_EVENT_SHUTDOWN;
|
||||||
|
gn->eq.post(sd);
|
||||||
|
|
||||||
|
std::vector<std::thread> th;
|
||||||
|
gn->threads_l.lock();
|
||||||
|
for(auto t=gn->threads.begin();t!=gn->threads.end();++t) {
|
||||||
|
t->second.run = false;
|
||||||
|
shutdown(t->first,SHUT_RDWR);
|
||||||
|
close(t->first);
|
||||||
|
th.emplace_back(t->second.thr);
|
||||||
|
}
|
||||||
|
gn->threads_l.unlock();
|
||||||
|
for(auto t=th.begin();t!=th.end();++t)
|
||||||
|
t->join();
|
||||||
|
|
||||||
|
delete gn->node;
|
||||||
|
delete gn;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ZT_Node *ZT_GoNode_getNode(ZT_GoNode *gn)
|
||||||
|
{
|
||||||
|
return gn->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets flags and socket options common to both IPv4 and IPv6 UDP sockets
|
||||||
|
static void setCommonUdpSocketSettings(ZT_SOCKET udpSock,const char *dev)
|
||||||
|
{
|
||||||
|
int bufSize = 1048576;
|
||||||
|
while (bufSize > 131072) {
|
||||||
|
if (setsockopt(udpSock,SOL_SOCKET,SO_RCVBUF,(const char *)&bufSize,sizeof(bufSize)) == 0)
|
||||||
|
break;
|
||||||
|
bufSize -= 131072;
|
||||||
|
}
|
||||||
|
bufSize = 1048576;
|
||||||
|
while (bufSize > 131072) {
|
||||||
|
if (setsockopt(udpSock,SOL_SOCKET,SO_SNDBUF,(const char *)&bufSize,sizeof(bufSize)) == 0)
|
||||||
|
break;
|
||||||
|
bufSize -= 131072;
|
||||||
|
}
|
||||||
|
|
||||||
|
SETSOCKOPT_FLAG_TYPE fl;
|
||||||
|
|
||||||
|
#ifdef SO_REUSEPORT
|
||||||
|
fl = SETSOCKOPT_FLAG_TRUE;
|
||||||
|
setsockopt(udpSock,SOL_SOCKET,SO_REUSEPORT,(void *)&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
#ifndef __LINUX__ // linux wants just SO_REUSEPORT
|
||||||
|
fl = SETSOCKOPT_FLAG_TRUE;
|
||||||
|
setsockopt(udpSock,SOL_SOCKET,SO_REUSEADDR,(void *)&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fl = SETSOCKOPT_FLAG_TRUE;
|
||||||
|
setsockopt(udpSock,SOL_SOCKET,SO_BROADCAST,(void *)&fl,sizeof(fl));
|
||||||
|
|
||||||
|
#ifdef IP_DONTFRAG
|
||||||
|
fl = SETSOCKOPT_FLAG_FALSE;
|
||||||
|
setsockopt(udpSock,IPPROTO_IP,IP_DONTFRAG,(void *)&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
#ifdef IP_MTU_DISCOVER
|
||||||
|
fl = SETSOCKOPT_FLAG_FALSE;
|
||||||
|
setsockopt(udpSock,IPPROTO_IP,IP_MTU_DISCOVER,(void *)&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SO_BINDTODEVICE
|
||||||
|
if ((dev)&&(strlen(dev)))
|
||||||
|
setsockopt(udpSock,SOL_SOCKET,SO_BINDTODEVICE,dev,strlen(dev));
|
||||||
|
#endif
|
||||||
|
#if defined(__BSD__) && defined(IP_BOUND_IF)
|
||||||
|
if ((dev)&&(strlen(dev))) {
|
||||||
|
int idx = if_nametoindex(dev);
|
||||||
|
if (idx != 0)
|
||||||
|
setsockopt(udpSock,IPPROTO_IP,IP_BOUND_IF,(void *)&idx,sizeof(idx));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int ZT_GoNode_phyStartListen(ZT_GoNode *gn,const char *dev,const char *ip,const int port)
|
||||||
|
{
|
||||||
|
if (strchr(ip,':')) {
|
||||||
|
struct sockaddr_in6 in6;
|
||||||
|
memset(&in6,0,sizeof(in6));
|
||||||
|
in6.sin6_family = AF_INET6;
|
||||||
|
if (inet_pton(AF_INET6,ip,&(in6.sin6_addr)) <= 0)
|
||||||
|
return errno;
|
||||||
|
in6.sin6_port = htons((uint16_t)port);
|
||||||
|
|
||||||
|
ZT_SOCKET udpSock = socket(AF_INET6,SOCK_DGRAM,0);
|
||||||
|
if (udpSock == ZT_INVALID_SOCKET)
|
||||||
|
return errno;
|
||||||
|
setCommonUdpSocketSettings(udpSock,dev);
|
||||||
|
SETSOCKOPT_FLAG_TYPE fl = SETSOCKOPT_FLAG_TRUE;
|
||||||
|
setsockopt(udpSock,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&fl,sizeof(fl));
|
||||||
|
#ifdef IPV6_DONTFRAG
|
||||||
|
fl = SETSOCKOPT_FLAG_FALSE;
|
||||||
|
setsockopt(udpSock,IPPROTO_IPV6,IPV6_DONTFRAG,&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bind(udpSock,reinterpret_cast<const struct sockaddr *>(&in6),sizeof(in6)) != 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(gn->threads_l);
|
||||||
|
ZT_GoNodeThread &gnt = gn->threads[udpSock];
|
||||||
|
gnt.ip = ip;
|
||||||
|
gnt.port = port;
|
||||||
|
gnt.af = AF_INET6;
|
||||||
|
gnt.run = true;
|
||||||
|
gnt.thr = std::thread([udpSock,gn,&gnt] {
|
||||||
|
struct sockaddr_in6 in6;
|
||||||
|
socklen_t salen;
|
||||||
|
char buf[16384];
|
||||||
|
while (gnt.run) {
|
||||||
|
salen = sizeof(in6);
|
||||||
|
int s = (int)recvfrom(udpSock,buf,sizeof(buf),0,reinterpret_cast<struct sockaddr *>(&in6),&salen);
|
||||||
|
if (s > 0) {
|
||||||
|
gn->node->processWirePacket(&gnt,OSUtils::now(),(int64_t)udpSock,reinterpret_cast<const struct sockaddr_storage *>(&in6),buf,(unsigned int)s,&(gn->nextBackgroundTaskDeadline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in in;
|
||||||
|
memset(&in,0,sizeof(in));
|
||||||
|
in.sin_family = AF_INET;
|
||||||
|
if (inet_pton(AF_INET,ip,&(in.sin_addr)) <= 0)
|
||||||
|
return errno;
|
||||||
|
in.sin_port = htons((uint16_t)port);
|
||||||
|
|
||||||
|
ZT_SOCKET udpSock = socket(AF_INET,SOCK_DGRAM,0);
|
||||||
|
if (udpSock == ZT_INVALID_SOCKET)
|
||||||
|
return errno;
|
||||||
|
setCommonUdpSocketSettings(udpSock,dev);
|
||||||
|
#ifdef SO_NO_CHECK
|
||||||
|
SETSOCKOPT_FLAG_TYPE fl = SETSOCKOPT_FLAG_TRUE;
|
||||||
|
setsockopt(udpSock,SOL_SOCKET,SO_NO_CHECK,&fl,sizeof(fl));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bind(udpSock,reinterpret_cast<const struct sockaddr *>(&in),sizeof(in)) != 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(gn->threads_l);
|
||||||
|
ZT_GoNodeThread &gnt = gn->threads[udpSock];
|
||||||
|
gnt.ip = ip;
|
||||||
|
gnt.port = port;
|
||||||
|
gnt.af = AF_INET6;
|
||||||
|
gnt.run = true;
|
||||||
|
gnt.thr = std::thread([udpSock,gn,&gnt] {
|
||||||
|
struct sockaddr_in in4;
|
||||||
|
socklen_t salen;
|
||||||
|
char buf[16384];
|
||||||
|
while (gnt.run) {
|
||||||
|
salen = sizeof(in4);
|
||||||
|
int s = (int)recvfrom(udpSock,buf,sizeof(buf),0,reinterpret_cast<struct sockaddr *>(&in4),&salen);
|
||||||
|
if (s > 0) {
|
||||||
|
gn->node->processWirePacket(&gnt,OSUtils::now(),(int64_t)udpSock,reinterpret_cast<const struct sockaddr_storage *>(&in4),buf,(unsigned int)s,&(gn->nextBackgroundTaskDeadline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int ZT_GoNode_phyStopListen(ZT_GoNode *gn,const char *dev,const char *ip,const int port)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(gn->threads_l);
|
||||||
|
for(auto t=gn->threads.begin();t!=gn->threads.end();) {
|
||||||
|
if ((t->second.ip == ip)&&(t->second.port == port)) {
|
||||||
|
t->second.run = false;
|
||||||
|
shutdown(t->first,SHUT_RDWR);
|
||||||
|
close(t->first);
|
||||||
|
t->second.thr.join();
|
||||||
|
gn->threads.erase(t++);
|
||||||
|
} else ++t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int ZT_GoNode_waitForEvent(ZT_GoNode *gn,ZT_GoNodeEvent *ev)
|
||||||
|
{
|
||||||
|
gn->eq.get(*ev);
|
||||||
|
}
|
100
go/native/GoNode.h
Normal file
100
go/native/GoNode.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2019 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2023-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by vergnn 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#ifndef ZT_GONODE_H
|
||||||
|
#define ZT_GONODE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../include/ZeroTierCore.h"
|
||||||
|
|
||||||
|
struct ZT_GoNode_Impl;
|
||||||
|
typedef struct ZT_GoNode_Impl ZT_GoNode;
|
||||||
|
|
||||||
|
#define ZT_GONODE_EVENT_SHUTDOWN 0
|
||||||
|
#define ZT_GONODE_EVENT_ZTEVENT 1
|
||||||
|
#define ZT_GONODE_EVENT_DNS_GET_TXT 2
|
||||||
|
#define ZT_GONODE_EVENT_STATE_PUT 3
|
||||||
|
#define ZT_GONODE_EVENT_STATE_DELETE 4
|
||||||
|
#define ZT_GONODE_EVENT_NETWORK_CONFIG_UPDATE 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant type for async core generated events pulled via waitForEvent
|
||||||
|
*/
|
||||||
|
struct ZT_GoNodeEvent_Impl
|
||||||
|
{
|
||||||
|
#ifdef __cplusplus
|
||||||
|
inline ZT_GoNodeEvent_Impl() { memset(reinterpret_cast<void *>(this),0,sizeof(ZT_GoNodeEvent_Impl)); }
|
||||||
|
inline ZT_GoNodeEvent_Impl(const ZT_GoNodeEvent &ev) { memcpy(reinterpret_cast<void *>(this),reinterpret_cast<const void *>(&ev),sizeof(ZT_GoNodeEvent_Impl)); }
|
||||||
|
inline ZT_GoNodeEvent_Impl &operator=(const ZT_GoNodeEvent_Impl &ev) { memcpy(reinterpret_cast<void *>(this),reinterpret_cast<const void *>(&ev),sizeof(ZT_GoNodeEvent_Impl)); return *this; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/* ZeroTier event of ZT_Event type */
|
||||||
|
struct {
|
||||||
|
int type;
|
||||||
|
} zt;
|
||||||
|
|
||||||
|
/* DNS resolution request */
|
||||||
|
struct {
|
||||||
|
uintptr_t requestId;
|
||||||
|
char dnsName[256];
|
||||||
|
} dns;
|
||||||
|
|
||||||
|
/* State object put or delete request */
|
||||||
|
struct {
|
||||||
|
uint8_t data[ZT_MAX_STATE_OBJECT_SIZE];
|
||||||
|
unsigned int len;
|
||||||
|
int objType;
|
||||||
|
uint64_t id[2];
|
||||||
|
} sobj;
|
||||||
|
|
||||||
|
/* Network configuration update event */
|
||||||
|
struct {
|
||||||
|
int op; /* ZT_VirtualNetworkConfigOperation */
|
||||||
|
ZT_VirtualNetworkConfig conf;
|
||||||
|
} nconf;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ZT_GoNodeEvent_Impl ZT_GoNodeEvent;
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ZT_GoNode *ZT_GoNode_new(
|
||||||
|
int (*goPathCheckFunc)(ZT_GoNode *,ZT_Node *,uint64_t ztAddress,const void *),
|
||||||
|
int (*goPathLookupFunc)(ZT_GoNode *,ZT_Node *,int desiredAddressFamily,void *),
|
||||||
|
int (*goStateObjectGetFunc)(ZT_GoNode *,ZT_Node *,int objType,const uint64_t id[2],void *buf,unsigned int bufSize)
|
||||||
|
);
|
||||||
|
|
||||||
|
void ZT_GoNode_delete(ZT_GoNode *gn);
|
||||||
|
|
||||||
|
ZT_Node *ZT_GoNode_getNode(ZT_GoNode *gn);
|
||||||
|
|
||||||
|
int ZT_GoNode_phyStartListen(ZT_GoNode *gn,const char *dev,const char *ip,const int port);
|
||||||
|
|
||||||
|
int ZT_GoNode_phyStopListen(ZT_GoNode *gn,const char *dev,const char *ip,const int port);
|
||||||
|
|
||||||
|
int ZT_GoNode_waitForEvent(ZT_GoNode *gn,ZT_GoNodeEvent *ev);
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
122
go/pkg/ztnode/errors.go
Normal file
122
go/pkg/ztnode/errors.go
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2019 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2023-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
package ztnode
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
// errTypeName returns the type name of an error minus any leading * character.
|
||||||
|
func errTypeName(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
et := reflect.TypeOf(err)
|
||||||
|
if et.Kind() == reflect.Ptr {
|
||||||
|
return et.Elem().Name()
|
||||||
|
}
|
||||||
|
return et.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Err indicates a general LF error such as an invalid parameter or state.
|
||||||
|
type Err string
|
||||||
|
|
||||||
|
func (e Err) Error() string { return (string)(e) }
|
||||||
|
|
||||||
|
// General errors
|
||||||
|
const (
|
||||||
|
ErrInvalidPublicKey Err = "invalid public key"
|
||||||
|
ErrInvalidPrivateKey Err = "invalid private key"
|
||||||
|
ErrInvalidParameter Err = "invalid parameter"
|
||||||
|
ErrInvalidObject Err = "invalid object"
|
||||||
|
ErrUnsupportedType Err = "unsupported type"
|
||||||
|
ErrUnsupportedCurve Err = "unsupported ECC curve (for this purpose)"
|
||||||
|
ErrOutOfRange Err = "parameter out of range"
|
||||||
|
ErrWharrgarblFailed Err = "Wharrgarbl proof of work algorithm failed (out of memory?)"
|
||||||
|
ErrIO Err = "I/O error"
|
||||||
|
ErrIncorrectKey Err = "incorrect key"
|
||||||
|
ErrAlreadyConnected Err = "already connected"
|
||||||
|
ErrRecordNotFound Err = "record not found"
|
||||||
|
ErrRecordIsNewer Err = "record is newer than timestamp"
|
||||||
|
ErrPulseSpanExeceeded Err = "pulse is more than one year after record"
|
||||||
|
ErrDuplicateRecord Err = "duplicate record"
|
||||||
|
ErrPrivateKeyRequired Err = "private key required"
|
||||||
|
ErrInvalidMessageSize Err = "message size invalid"
|
||||||
|
ErrQueryRequiresSelectors Err = "query requires at least one selector"
|
||||||
|
ErrQueryInvalidSortOrder Err = "invalid sort order value"
|
||||||
|
ErrAlreadyMounted Err = "mount point already mounted"
|
||||||
|
)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ErrRecord indicates an error related to an invalid record or a record failing a check.
|
||||||
|
type ErrRecord string
|
||||||
|
|
||||||
|
func (e ErrRecord) Error() string { return (string)(e) }
|
||||||
|
|
||||||
|
// Errs indicating that a record is invalid
|
||||||
|
const (
|
||||||
|
ErrRecordInvalid ErrRecord = "record invalid"
|
||||||
|
ErrRecordOwnerSignatureCheckFailed ErrRecord = "owner signature check failed"
|
||||||
|
ErrRecordInsufficientWork ErrRecord = "insufficient work to pay for this record"
|
||||||
|
ErrRecordNotApproved ErrRecord = "record not currently approved (via proof of work and/or certificates)"
|
||||||
|
ErrRecordInsufficientLinks ErrRecord = "insufficient links"
|
||||||
|
ErrRecordTooManyLinks ErrRecord = "too many links"
|
||||||
|
ErrRecordInvalidLinks ErrRecord = "links must be sorted and unique"
|
||||||
|
ErrRecordTooManySelectors ErrRecord = "too many selectors"
|
||||||
|
ErrRecordUnsupportedAlgorithm ErrRecord = "unsupported algorithm or type"
|
||||||
|
ErrRecordTooLarge ErrRecord = "record too large"
|
||||||
|
ErrRecordValueTooLarge ErrRecord = "record value too large"
|
||||||
|
ErrRecordViolatesSpecialRelativity ErrRecord = "record timestamp too far in the future"
|
||||||
|
ErrRecordTooOld ErrRecord = "record older than network timestamp floor"
|
||||||
|
ErrRecordCertificateInvalid ErrRecord = "certificate invalid"
|
||||||
|
ErrRecordCertificateRequired ErrRecord = "certificate required"
|
||||||
|
ErrRecordProhibited ErrRecord = "record administratively prohibited"
|
||||||
|
)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ErrDatabase contains information about a database related problem.
|
||||||
|
type ErrDatabase struct {
|
||||||
|
// ErrCode is the error code returned by the C database module.
|
||||||
|
ErrCode int
|
||||||
|
|
||||||
|
// ErrMessage is an error message supplied by the C code or by Go (optional)
|
||||||
|
ErrMessage string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrDatabase) Error() string {
|
||||||
|
return fmt.Sprintf("database error: %d (%s)", e.ErrCode, e.ErrMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ErrAPI (response) indicates an error and is returned with non-200 responses.
|
||||||
|
type ErrAPI struct {
|
||||||
|
Code int `` // HTTP response code
|
||||||
|
Message string `json:",omitempty"` // Message indicating the reason for the error
|
||||||
|
ErrTypeName string `json:",omitempty"` // Name of LF native error or empty if HTTP or transport error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface, making APIError an 'error' in the Go sense.
|
||||||
|
func (e ErrAPI) Error() string {
|
||||||
|
if len(e.ErrTypeName) > 0 {
|
||||||
|
return fmt.Sprintf("%d:%s:%s", e.Code, e.ErrTypeName, e.Message)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d:%s", e.Code, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
*/
|
19
go/pkg/ztnode/misc.go
Normal file
19
go/pkg/ztnode/misc.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2019 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2023-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
package ztnode
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// TimeMs returns the time in milliseconds since epoch.
|
||||||
|
func TimeMs() int64 { return int64(time.Now().UnixNano()) / int64(1000000) }
|
48
go/pkg/ztnode/node.go
Normal file
48
go/pkg/ztnode/node.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2019 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2023-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
package ztnode
|
||||||
|
|
||||||
|
//#cgo CFLAGS: -O3
|
||||||
|
//#cgo LDFLAGS: ${SRCDIR}/../../../build/node/libzt_core.a -lc++
|
||||||
|
//#define ZT_CGO 1
|
||||||
|
//#include <stdint.h>
|
||||||
|
//#include "../../../include/ZeroTierCore.h"
|
||||||
|
//#if __has_include("../../../version.h")
|
||||||
|
//#include "../../../version.h"
|
||||||
|
//#else
|
||||||
|
//#define ZEROTIER_ONE_VERSION_MAJOR 255
|
||||||
|
//#define ZEROTIER_ONE_VERSION_MINOR 255
|
||||||
|
//#define ZEROTIER_ONE_VERSION_REVISION 255
|
||||||
|
//#define ZEROTIER_ONE_VERSION_BUILD 255
|
||||||
|
//#endif
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CoreVersionMajor is the major version of the ZeroTier core
|
||||||
|
CoreVersionMajor int = C.ZEROTIER_ONE_VERSION_MAJOR
|
||||||
|
|
||||||
|
// CoreVersionMinor is the minor version of the ZeroTier core
|
||||||
|
CoreVersionMinor int = C.ZEROTIER_ONE_VERSION_MINOR
|
||||||
|
|
||||||
|
// CoreVersionRevision is the revision of the ZeroTier core
|
||||||
|
CoreVersionRevision int = C.ZEROTIER_ONE_VERSION_REVISION
|
||||||
|
|
||||||
|
// CoreVersionBuild is the build version of the ZeroTier core
|
||||||
|
CoreVersionBuild int = C.ZEROTIER_ONE_VERSION_BUILD
|
||||||
|
)
|
||||||
|
|
||||||
|
// Node is an instance of a ZeroTier node
|
||||||
|
type Node struct {
|
||||||
|
node *C.ZT_Node
|
||||||
|
}
|
|
@ -166,6 +166,11 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024
|
#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum size for a state object (via state object put/get callbacks/API)
|
||||||
|
*/
|
||||||
|
#define ZT_MAX_STATE_OBJECT_SIZE 4096
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum value for link quality (min is 0)
|
* Maximum value for link quality (min is 0)
|
||||||
*/
|
*/
|
||||||
|
@ -1319,7 +1324,7 @@ typedef struct
|
||||||
/**
|
/**
|
||||||
* Whether this peer was ever reachable via an aggregate link
|
* Whether this peer was ever reachable via an aggregate link
|
||||||
*/
|
*/
|
||||||
bool hadAggregateLink;
|
int hadAggregateLink;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Known network paths to peer
|
* Known network paths to peer
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "Thread.hpp"
|
#include "../node/Constants.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -32,16 +33,23 @@ template <class T>
|
||||||
class BlockingQueue
|
class BlockingQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BlockingQueue(void) : r(true) {}
|
enum TimedWaitResult
|
||||||
|
{
|
||||||
|
OK,
|
||||||
|
TIMED_OUT,
|
||||||
|
STOP
|
||||||
|
};
|
||||||
|
|
||||||
inline void post(T t)
|
ZT_ALWAYS_INLINE BlockingQueue(void) : r(true) {}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE void post(T t)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m);
|
std::lock_guard<std::mutex> lock(m);
|
||||||
q.push(t);
|
q.push(t);
|
||||||
c.notify_one();
|
c.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void postLimit(T t,const unsigned long limit)
|
ZT_ALWAYS_INLINE void postLimit(T t,const unsigned long limit)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m);
|
std::unique_lock<std::mutex> lock(m);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -56,7 +64,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void stop(void)
|
ZT_ALWAYS_INLINE void stop(void)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m);
|
std::lock_guard<std::mutex> lock(m);
|
||||||
r = false;
|
r = false;
|
||||||
|
@ -64,7 +72,7 @@ public:
|
||||||
gc.notify_all();
|
gc.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool get(T &value)
|
ZT_ALWAYS_INLINE bool get(T &value)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m);
|
std::unique_lock<std::mutex> lock(m);
|
||||||
if (!r) return false;
|
if (!r) return false;
|
||||||
|
@ -81,14 +89,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TimedWaitResult
|
ZT_ALWAYS_INLINE TimedWaitResult get(T &value,const unsigned long ms)
|
||||||
{
|
|
||||||
OK,
|
|
||||||
TIMED_OUT,
|
|
||||||
STOP
|
|
||||||
};
|
|
||||||
|
|
||||||
inline TimedWaitResult get(T &value,const unsigned long ms)
|
|
||||||
{
|
{
|
||||||
const std::chrono::milliseconds ms2{ms};
|
const std::chrono::milliseconds ms2{ms};
|
||||||
std::unique_lock<std::mutex> lock(m);
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
@ -105,7 +106,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
volatile bool r;
|
std::atomic_bool r;
|
||||||
std::queue<T> q;
|
std::queue<T> q;
|
||||||
mutable std::mutex m;
|
mutable std::mutex m;
|
||||||
mutable std::condition_variable c,gc;
|
mutable std::condition_variable c,gc;
|
||||||
|
|
Loading…
Add table
Reference in a new issue