Browse Source

More Go boilerplate.

Adam Ierymenko 5 years ago
parent
commit
ed2024285d
7 changed files with 154 additions and 11 deletions
  1. 2 2
      go/native/CMakeLists.txt
  2. 72 3
      go/native/GoGlue.cpp
  3. 49 4
      go/native/GoGlue.h
  4. 13 0
      include/ZeroTierCore.h
  5. 2 2
      node/MAC.hpp
  6. 15 0
      node/Node.cpp
  7. 1 0
      node/Node.hpp

+ 2 - 2
go/native/CMakeLists.txt

@@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 2.8)
 project(zt_go_native)
 
 set(src
-	GoNode.cpp
+	GoGlue.cpp
 )
 
 set(headers
-	GoNode.h
+	GoGlue.h
 )
 
 add_library(${PROJECT_NAME} STATIC ${src} ${headers})

+ 72 - 3
go/native/GoNode.cpp → go/native/GoGlue.cpp

@@ -11,12 +11,14 @@
  */
 /****/
 
-#include "GoNode.h"
+#include "GoGlue.h"
 
 #include "../../node/Constants.hpp"
 #include "../../node/InetAddress.hpp"
 #include "../../node/Node.hpp"
 #include "../../node/Utils.hpp"
+#include "../../node/MAC.hpp"
+#include "../../node/Address.hpp"
 #include "../../osdep/OSUtils.hpp"
 #include "../../osdep/BlockingQueue.hpp"
 #include "../../osdep/EthernetTap.hpp"
@@ -55,6 +57,7 @@
 #include <vector>
 #include <array>
 #include <set>
+#include <memory>
 
 #ifdef __WINDOWS__
 #define SETSOCKOPT_FLAG_TYPE BOOL
@@ -90,10 +93,18 @@ struct ZT_GoNode_Impl
 	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::string path;
+	std::atomic_bool run;
+
 	std::map< ZT_SOCKET,ZT_GoNodeThread > threads;
 	std::mutex threads_l;
 
+	std::map< uint64_t,std::shared_ptr<EthernetTap> > taps;
+	std::mutex taps_l;
+
 	BlockingQueue<ZT_GoNodeEvent> eq;
+
+	std::thread backgroundTaskThread;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -273,10 +284,10 @@ static void ZT_GoNode_DNSResolver(
 //////////////////////////////////////////////////////////////////////////////
 
 extern "C" ZT_GoNode *ZT_GoNode_new(
+	const char *workingPath,
 	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)
-)
+	int (*goStateObjectGetFunc)(ZT_GoNode *,ZT_Node *,int objType,const uint64_t id[2],void *buf,unsigned int bufSize))
 {
 	try {
 		struct ZT_Node_Callbacks cb;
@@ -296,6 +307,18 @@ extern "C" ZT_GoNode *ZT_GoNode_new(
 		gn->goPathCheckFunc = goPathCheckFunc;
 		gn->goPathLookupFunc = goPathLookupFunc;
 		gn->goStateObjectGetFunc = goStateObjectGetFunc;
+		gn->path = workingPath;
+		gn->run = true;
+
+		gn->backgroundTaskThread = std::thread([gn] {
+			while (gn->run) {
+				std::this_thread::sleep_for(std::chrono::milliseconds(250));
+				const int64_t now = OSUtils::now();
+				if (now >= gn->nextBackgroundTaskDeadline)
+					gn->node->processBackgroundTasks(nullptr,now,&(gn->nextBackgroundTaskDeadline));
+			}
+		});
+
 		return gn;
 	} catch ( ... ) {
 		fprintf(stderr,"FATAL: unable to create new instance of Node (out of memory?)" ZT_EOL_S);
@@ -305,6 +328,8 @@ extern "C" ZT_GoNode *ZT_GoNode_new(
 
 extern "C" void ZT_GoNode_delete(ZT_GoNode *gn)
 {
+	gn->run = false;
+
 	ZT_GoNodeEvent sd;
 	sd.type = ZT_GONODE_EVENT_SHUTDOWN;
 	gn->eq.post(sd);
@@ -321,6 +346,14 @@ extern "C" void ZT_GoNode_delete(ZT_GoNode *gn)
 	for(auto t=th.begin();t!=th.end();++t)
 		t->join();
 
+	gn->taps_l.lock();
+	for(auto t=gn->taps.begin();t!=gn->taps.end();++t)
+		gn->node->leave(t->first,nullptr,nullptr);
+	gn->taps.clear();
+	gn->taps_l.unlock();
+
+	gn->backgroundTaskThread.join();
+
 	delete gn->node;
 	delete gn;
 }
@@ -491,3 +524,39 @@ extern "C" int ZT_GoNode_waitForEvent(ZT_GoNode *gn,ZT_GoNodeEvent *ev)
 {
 	gn->eq.get(*ev);
 }
+
+static void tapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
+{
+	ZT_GoNode *const gn = reinterpret_cast<ZT_GoNode *>(uptr);
+	gn->node->processVirtualNetworkFrame(tptr,OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&(gn->nextBackgroundTaskDeadline));
+}
+
+extern "C" ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid)
+{
+	try {
+		std::lock_guard<std::mutex> l(gn->taps_l);
+		auto existingTap = gn->taps.find(nwid);
+		if (existingTap != gn->taps.end())
+			return (ZT_GoTap *)existingTap->second.get();
+		char tmp[256];
+		OSUtils::ztsnprintf(tmp,sizeof(tmp),"ZeroTier Network %.16llx",(unsigned long long)nwid);
+		std::shared_ptr<EthernetTap> tap(EthernetTap::newInstance(nullptr,gn->path.c_str(),MAC(Address(gn->node->address()),nwid),ZT_DEFAULT_MTU,0,nwid,tmp,&tapFrameHandler,gn));
+		if (!tap)
+			return nullptr;
+		gn->taps[nwid] = tap;
+		gn->node->join(nwid,tap.get(),nullptr);
+		return (ZT_GoTap *)tap.get();
+	} catch ( ... ) {
+		return nullptr;
+	}
+}
+
+extern "C" void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid)
+{
+	std::lock_guard<std::mutex> l(gn->taps_l);
+	auto existingTap = gn->taps.find(nwid);
+	if (existingTap != gn->taps.end()) {
+		gn->node->leave(nwid,nullptr,nullptr);
+		gn->taps.erase(existingTap);
+	}
+}

+ 49 - 4
go/native/GoNode.h → go/native/GoGlue.h

@@ -20,6 +20,14 @@
 
 #include "../../include/ZeroTierCore.h"
 
+/****************************************************************************/
+
+/* A pointer to an instance of EthernetTap */
+typedef void ZT_GoTap;
+
+/* ZT_GoNode is a C struct and functions that wraps ZT_Node for use via cgo. It
+ * performs UDP and other direct I/O in C for performance but otherwise lets
+ * the Go code control the node's behavior. */
 struct ZT_GoNode_Impl;
 typedef struct ZT_GoNode_Impl ZT_GoNode;
 
@@ -65,6 +73,7 @@ struct ZT_GoNodeEvent_Impl
 
 		/* Network configuration update event */
 		struct {
+			ZT_GoTap *tap;
 			int op; /* ZT_VirtualNetworkConfigOperation */
 			ZT_VirtualNetworkConfig conf;
 		} nconf;
@@ -73,27 +82,63 @@ struct ZT_GoNodeEvent_Impl
 
 typedef struct ZT_GoNodeEvent_Impl ZT_GoNodeEvent;
 
-#ifndef __cplusplus
+/****************************************************************************/
+
+#ifdef __cplusplus
 extern "C" {
 #endif
 
+/****************************************************************************/
+
 ZT_GoNode *ZT_GoNode_new(
+	const char *workingPath,
 	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)
-);
+	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);
 
+/* This can be called more than once to start multiple listener threads */
 int ZT_GoNode_phyStartListen(ZT_GoNode *gn,const char *dev,const char *ip,const int port);
 
+/* Close all listener threads for a given local IP and 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
+ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid);
+
+void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid);
+
+/****************************************************************************/
+
+void ZT_GoTap_setEnabled(ZT_GoTap *tap,int enabled);
+
+int ZT_GoTap_addIp(ZT_GoTap *tap,int af,const void *ip,int port);
+
+int ZT_GoTap_removeIp(ZT_GoTap *tap,int af,const void *ip,int port);
+
+/* The buf buffer is filled with tuplies of:
+ *   uint8_t family
+ *   uint8_t ip[4 or 16]
+ *   uint16_t port (big-endian byte order)
+ *
+ * This function returns the number of such tuples in the result.
+ * If the buffer isn't big enough results are incomplete.
+ */
+int ZT_GoTap_ips(ZT_GoTap *tap,void *buf,unsigned int bufSize);
+
+const char *ZT_GoTap_deviceName(ZT_GoTap *tap);
+
+void ZT_GoTap_setFriendlyName(ZT_GoTap *tap,const char *friendlyName);
+
+void ZT_GoTap_setMtu(ZT_GoTap *tap,unsigned int mtu);
+
+/****************************************************************************/
+
+#ifdef __cplusplus
 }
 #endif
 

+ 13 - 0
include/ZeroTierCore.h

@@ -1851,6 +1851,7 @@ ZT_SDK_API void ZT_Node_processDNSResult(
  * @param node Node instance
  * @param nwid 64-bit ZeroTier network ID
  * @param uptr An arbitrary pointer to associate with this network (default: NULL)
+ * @param tptr Thread pointer to pass to functions/callbacks resulting from this call
  * @return OK (0) or error code if a fatal error condition has occurred
  */
 ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr);
@@ -1868,6 +1869,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *upt
  * @param node Node instance
  * @param nwid 64-bit network ID
  * @param uptr Target pointer is set to uptr (if not NULL)
+ * @param tptr Thread pointer to pass to functions/callbacks resulting from this call
  * @return OK (0) or error code if a fatal error condition has occurred
  */
 ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr);
@@ -2015,6 +2017,17 @@ ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t
  */
 ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node);
 
+/**
+ * Set the network-associated user-defined pointer for a given network
+ *
+ * This will have no effect if the network ID is not recognized.
+ *
+ * @param node Node instance
+ * @param nwid Network ID
+ * @param ptr New network-associated pointer
+ */
+ZT_SDK_API void ZT_Node_setNetworkUserPtr(ZT_Node *node,uint64_t nwid,void *ptr);
+
 /**
  * Free a query result buffer
  *

+ 2 - 2
node/MAC.hpp

@@ -41,8 +41,8 @@ public:
 		    ((((uint64_t)d) & 0xffULL) << 16) |
 		    ((((uint64_t)e) & 0xffULL) << 8) |
 		    (((uint64_t)f) & 0xffULL) ) {}
-				ZT_ALWAYS_INLINE MAC(const void *bits,unsigned int len) { setTo(bits,len); }
-				ZT_ALWAYS_INLINE MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
+	ZT_ALWAYS_INLINE MAC(const void *bits,unsigned int len) { setTo(bits,len); }
+	ZT_ALWAYS_INLINE MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
 	ZT_ALWAYS_INLINE MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
 
 	/**

+ 15 - 0
node/Node.cpp

@@ -598,6 +598,14 @@ ZT_VirtualNetworkList *Node::networks() const
 	return nl;
 }
 
+void Node::setNetworkUserPtr(uint64_t nwid,void *ptr)
+{
+	Mutex::Lock _l(_networks_m);
+	const SharedPtr<Network> *const nw = _networks.get(nwid);
+	if (nw)
+		*((*nw)->userPtr()) = ptr;
+}
+
 void Node::freeQueryResult(void *qr)
 {
 	if (qr)
@@ -1011,6 +1019,13 @@ ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node)
 	}
 }
 
+void ZT_Node_setNetworkUserPtr(ZT_Node *node,uint64_t nwid,void *ptr)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->setNetworkUserPtr(nwid,ptr);
+	} catch ( ... ) {}
+}
+
 void ZT_Node_freeQueryResult(ZT_Node *node,void *qr)
 {
 	try {

+ 1 - 0
node/Node.hpp

@@ -102,6 +102,7 @@ public:
 	ZT_PeerList *peers() const;
 	ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
 	ZT_VirtualNetworkList *networks() const;
+	void setNetworkUserPtr(uint64_t nwid,void *ptr);
 	void freeQueryResult(void *qr);
 	int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
 	void clearLocalInterfaceAddresses();