Browse Source

Move C API into its own source file, and fix some build flags to mirror fix in 1.6.0 to run on old Atom processors.

Adam Ierymenko 4 years ago
parent
commit
8f746f5099
13 changed files with 760 additions and 715 deletions
  1. 5 2
      CMakeLists.txt
  2. 2 0
      core/Address.hpp
  3. 3 0
      core/Blob.hpp
  4. 704 0
      core/CAPI.cpp
  5. 1 0
      core/CMakeLists.txt
  6. 0 154
      core/Certificate.cpp
  7. 0 98
      core/Identity.cpp
  8. 0 119
      core/Locator.cpp
  9. 2 0
      core/MAC.hpp
  10. 0 317
      core/Node.cpp
  11. 15 10
      core/OS.hpp
  12. 0 1
      core/Topology.hpp
  13. 28 14
      core/Utils.cpp

+ 5 - 2
CMakeLists.txt

@@ -219,10 +219,13 @@ if(NOT PACKAGE_STATIC)
 	if (
 	if (
 		CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
 		CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
 		CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR
 		CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR
-		CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64"
+		CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64" OR
+		CMAKE_SYSTEM_PROCESSOR MATCHES "X86_64" OR
+		CMAKE_SYSTEM_PROCESSOR MATCHES "x64" OR
+		CMAKE_SYSTEM_PROCESSOR MATCHES "X64"
 	)
 	)
 		message("++ Adding flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
 		message("++ Adding flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
-		add_compile_options(-maes -mrdrnd -mpclmul -msse -msse2 -mssse3 -msse4 -msse4.1 -msse4.2)
+		add_compile_options(-maes -mrdrnd -mpclmul -msse -msse2)
 	endif()
 	endif()
 
 
 	if (
 	if (

+ 2 - 0
core/Address.hpp

@@ -158,6 +158,8 @@ private:
 	uint64_t _a;
 	uint64_t _a;
 };
 };
 
 
+static_assert(sizeof(Address) == sizeof(uint64_t),"Address has unnecessary extra padding");
+
 } // namespace ZeroTier
 } // namespace ZeroTier
 
 
 #endif
 #endif

+ 3 - 0
core/Blob.hpp

@@ -112,6 +112,9 @@ struct UniqueID
 	{ return (memcmp(data, b.data, 16) >= 0); }
 	{ return (memcmp(data, b.data, 16) >= 0); }
 };
 };
 
 
+static_assert(sizeof(SHA384Hash) == 48,"SHA384Hash contains unnecessary padding");
+static_assert(sizeof(UniqueID) == 16,"UniqueID contains unnecessary padding");
+
 } // namespace ZeroTier
 } // namespace ZeroTier
 
 
 #endif
 #endif

+ 704 - 0
core/CAPI.cpp

@@ -0,0 +1,704 @@
+/*
+ * Copyright (c)2013-2020 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: 2025-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.
+ */
+/****/
+
+#include "Constants.hpp"
+#include "Node.hpp"
+#include "Identity.hpp"
+#include "Locator.hpp"
+#include "Certificate.hpp"
+
+extern "C" {
+
+/********************************************************************************************************************/
+
+// These macros make the idiom of passing buffers to outside code via the API work properly even
+// if the first address of Buf does not overlap with its data field, since the C++ standard does
+// not absolutely guarantee this.
+#define _ZT_PTRTOBUF(p) ((ZeroTier::Buf *)( ((uintptr_t)(p)) - ((uintptr_t)&(((ZeroTier::Buf *)0)->unsafeData[0])) ))
+#define _ZT_BUFTOPTR(b) ((void *)(&((b)->unsafeData[0])))
+
+void *ZT_getBuffer()
+{
+	// When external code requests a Buf, grab one from the pool (or freshly allocated)
+	// and return it with its reference count left at zero. It's the responsibility of
+	// external code to bring it back via freeBuffer() or one of the processX() calls.
+	// When this occurs it's either sent back to the pool with Buf's delete operator or
+	// wrapped in a SharedPtr<> to be passed into the core.
+	try {
+		return _ZT_BUFTOPTR(new ZeroTier::Buf());
+	} catch (...) {
+		return nullptr; // can only happen on out of memory condition
+	}
+}
+
+void ZT_freeBuffer(void *b)
+{
+	if (b)
+		delete _ZT_PTRTOBUF(b);
+}
+
+struct p_queryResultBase
+{
+	void (*freeFunction)(const void *);
+};
+
+void ZT_freeQueryResult(const void *qr)
+{
+	if ((qr) && (reinterpret_cast<const p_queryResultBase *>(qr)->freeFunction))
+		reinterpret_cast<const p_queryResultBase *>(qr)->freeFunction(qr);
+}
+
+void ZT_version(int *major, int *minor, int *revision, int *build)
+{
+	if (major)
+		*major = ZEROTIER_VERSION_MAJOR;
+	if (minor)
+		*minor = ZEROTIER_VERSION_MINOR;
+	if (revision)
+		*revision = ZEROTIER_VERSION_REVISION;
+	if (build)
+		*build = ZEROTIER_VERSION_BUILD;
+}
+
+/********************************************************************************************************************/
+
+enum ZT_ResultCode ZT_Node_new(ZT_Node **node, void *uptr, void *tptr, const struct ZT_Node_Callbacks *callbacks, int64_t now)
+{
+	*node = (ZT_Node *)0;
+	try {
+		*node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(uptr, tptr, callbacks, now));
+		return ZT_RESULT_OK;
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (std::runtime_error &exc) {
+		return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+void ZT_Node_delete(ZT_Node *node, void *tPtr)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->shutdown(tPtr);
+		delete (reinterpret_cast<ZeroTier::Node *>(node));
+	} catch (...) {}
+}
+
+enum ZT_ResultCode ZT_Node_processWirePacket(
+	ZT_Node *node,
+	void *tptr,
+	int64_t now,
+	int64_t localSocket,
+	const struct sockaddr_storage *remoteAddress,
+	const void *packetData,
+	unsigned int packetLength,
+	int isZtBuffer,
+	volatile int64_t *nextBackgroundTaskDeadline)
+{
+	try {
+		ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? _ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK));
+		return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr, now, localSocket, remoteAddress, buf, packetLength, nextBackgroundTaskDeadline);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		// "OK" since invalid packets are simply dropped, but the system is still up.
+		// We should never make it here, but if we did that would be the interpretation.
+		return ZT_RESULT_OK;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
+	ZT_Node *node,
+	void *tptr,
+	int64_t now,
+	uint64_t nwid,
+	uint64_t sourceMac,
+	uint64_t destMac,
+	unsigned int etherType,
+	unsigned int vlanId,
+	const void *frameData,
+	unsigned int frameLength,
+	int isZtBuffer,
+	volatile int64_t *nextBackgroundTaskDeadline)
+{
+	try {
+		ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? _ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData, frameLength & ZT_BUF_MEM_MASK));
+		return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(tptr, now, nwid, sourceMac, destMac, etherType, vlanId, buf, frameLength, nextBackgroundTaskDeadline);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node, void *tptr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(tptr, now, nextBackgroundTaskDeadline);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_join(ZT_Node *node, uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, void *tptr)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->join(nwid, controllerFingerprint, uptr, tptr);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_leave(ZT_Node *node, uint64_t nwid, void **uptr, void *tptr)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid, uptr, tptr);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node, void *tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->multicastSubscribe(tptr, nwid, multicastGroup, multicastAdi);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->multicastUnsubscribe(nwid, multicastGroup, multicastAdi);
+	} catch (std::bad_alloc &exc) {
+		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+uint64_t ZT_Node_address(ZT_Node *node)
+{
+	return reinterpret_cast<ZeroTier::Node *>(node)->address();
+}
+
+const ZT_Identity *ZT_Node_identity(ZT_Node *node)
+{
+	return (const ZT_Identity *)(&(reinterpret_cast<ZeroTier::Node *>(node)->identity()));
+}
+
+void ZT_Node_status(ZT_Node *node, ZT_NodeStatus *status)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->status(status);
+	} catch (...) {}
+}
+
+ZT_PeerList *ZT_Node_peers(ZT_Node *node)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->peers();
+	} catch (...) {
+		return (ZT_PeerList *)0;
+	}
+}
+
+ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node, uint64_t nwid)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->networkConfig(nwid);
+	} catch (...) {
+		return (ZT_VirtualNetworkConfig *)0;
+	}
+}
+
+ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->networks();
+	} catch (...) {
+		return (ZT_VirtualNetworkList *)0;
+	}
+}
+
+int ZT_Node_tryPeer(
+	ZT_Node *node,
+	void *tptr,
+	const ZT_Fingerprint *fp,
+	const ZT_Endpoint *endpoint,
+	int retries)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->tryPeer(tptr, fp, endpoint, retries);
+	} catch (...) {
+		return 0;
+	}
+}
+
+enum ZT_CertificateError ZT_Node_addCertificate(
+	ZT_Node *node,
+	void *tptr,
+	int64_t now,
+	unsigned int localTrust,
+	const ZT_Certificate *cert,
+	const void *certData,
+	unsigned int certSize)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->addCertificate(tptr, now, localTrust, cert, certData, certSize);
+	} catch (...) {
+		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+	}
+}
+
+ZT_SDK_API enum ZT_ResultCode ZT_Node_deleteCertificate(
+	ZT_Node *node,
+	void *tptr,
+	const void *serialNo)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->deleteCertificate(tptr, serialNo);
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates(ZT_Node *node)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->listCertificates();
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+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_setInterfaceAddresses(ZT_Node *node, const ZT_InterfaceAddress *addrs, unsigned int addrCount)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->setInterfaceAddresses(addrs, addrCount);
+	} catch (...) {}
+}
+
+enum ZT_ResultCode ZT_Node_addPeer(
+	ZT_Node *node,
+	void *tptr,
+	const ZT_Identity *id)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->addPeer(tptr, id);
+	} catch (...) {
+		return ZT_RESULT_ERROR_INTERNAL;
+	}
+}
+
+int ZT_Node_sendUserMessage(ZT_Node *node, void *tptr, uint64_t dest, uint64_t typeId, const void *data, unsigned int len)
+{
+	try {
+		return reinterpret_cast<ZeroTier::Node *>(node)->sendUserMessage(tptr, dest, typeId, data, len);
+	} catch (...) {
+		return 0;
+	}
+}
+
+void ZT_Node_setController(ZT_Node *node, void *networkControllerInstance)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->setController(networkControllerInstance);
+	} catch (...) {}
+}
+
+/********************************************************************************************************************/
+
+ZT_Locator *ZT_Locator_create(
+	int64_t ts,
+	const ZT_Endpoint *endpoints,
+	const ZT_EndpointAttributes *endpointAttributes, // TODO: not used yet
+	unsigned int endpointCount,
+	const ZT_Identity *signer)
+{
+	try {
+		if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
+			return nullptr;
+		ZeroTier::Locator *loc = new ZeroTier::Locator();
+		for (unsigned int i = 0;i < endpointCount;++i)
+			loc->add(reinterpret_cast< const ZeroTier::Endpoint * >(endpoints)[i], ZeroTier::Locator::EndpointAttributes::DEFAULT);
+		if (!loc->sign(ts, *reinterpret_cast< const ZeroTier::Identity * >(signer))) {
+			delete loc;
+			return nullptr;
+		}
+		return reinterpret_cast<ZT_Locator *>(loc);
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+ZT_Locator *ZT_Locator_fromString(const char *str)
+{
+	try {
+		if (!str)
+			return nullptr;
+		ZeroTier::Locator *loc = new ZeroTier::Locator();
+		if (!loc->fromString(str)) {
+			delete loc;
+			return nullptr;
+		}
+		return reinterpret_cast<ZT_Locator *>(loc);
+	} catch ( ... ) {
+		return nullptr;
+	}
+}
+
+ZT_Locator *ZT_Locator_unmarshal(
+	const void *data,
+	unsigned int len)
+{
+	try {
+		if ((!data) || (len == 0))
+			return nullptr;
+		ZeroTier::Locator *loc = new ZeroTier::Locator();
+		if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data), (int) len) <= 0) {
+			delete loc;
+			return nullptr;
+		}
+		return reinterpret_cast<ZT_Locator *>(loc);
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+int ZT_Locator_marshal(const ZT_Locator *loc, void *buf, unsigned int bufSize)
+{
+	if ((!loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX))
+		return -1;
+	return reinterpret_cast<const ZeroTier::Locator *>(loc)->marshal(reinterpret_cast<uint8_t *>(buf), (int) bufSize);
+}
+
+char *ZT_Locator_toString(
+	const ZT_Locator *loc,
+	char *buf,
+	int capacity)
+{
+	if ((!loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX))
+		return nullptr;
+	return reinterpret_cast<const ZeroTier::Locator *>(loc)->toString(buf);
+}
+
+const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc)
+{
+	if (!loc)
+		return nullptr;
+	return (ZT_Fingerprint *) (&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
+}
+
+int64_t ZT_Locator_timestamp(const ZT_Locator *loc)
+{
+	if (!loc)
+		return 0;
+	return reinterpret_cast<const ZeroTier::Locator *>(loc)->timestamp();
+}
+
+unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc)
+{
+	return (loc) ? (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()) : 0;
+}
+
+const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc, const unsigned int ep)
+{
+	if (!loc)
+		return nullptr;
+	if (ep >= (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()))
+		return nullptr;
+	return reinterpret_cast<const ZT_Endpoint *>(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints()[ep]));
+}
+
+int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer)
+{
+	if ((!loc) || (!signer))
+		return 0;
+	return reinterpret_cast<const ZeroTier::Locator *>(loc)->verify(*reinterpret_cast<const ZeroTier::Identity *>(signer)) ? 1 : 0;
+}
+
+void ZT_Locator_delete(ZT_Locator *loc)
+{
+	if (loc)
+		delete reinterpret_cast<ZeroTier::Locator *>(loc);
+}
+
+/********************************************************************************************************************/
+
+ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type)
+{
+	if ((type != ZT_IDENTITY_TYPE_C25519) && (type != ZT_IDENTITY_TYPE_P384))
+		return nullptr;
+	try {
+		ZeroTier::Identity *const id = new ZeroTier::Identity();
+		id->generate((ZeroTier::Identity::Type)type);
+		return reinterpret_cast<ZT_Identity *>(id);
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+ZT_Identity *ZT_Identity_fromString(const char *idStr)
+{
+	if (!idStr)
+		return nullptr;
+	try {
+		ZeroTier::Identity *const id = new ZeroTier::Identity();
+		if (!id->fromString(idStr)) {
+			delete id;
+			return nullptr;
+		}
+		return reinterpret_cast<ZT_Identity *>(id);
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+int ZT_Identity_validate(const ZT_Identity *id)
+{
+	if (!id)
+		return 0;
+	return reinterpret_cast<const ZeroTier::Identity *>(id)->locallyValidate() ? 1 : 0;
+}
+
+unsigned int ZT_Identity_sign(const ZT_Identity *id, const void *data, unsigned int len, void *signature, unsigned int signatureBufferLength)
+{
+	if (!id)
+		return 0;
+	if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE)
+		return 0;
+	return reinterpret_cast<const ZeroTier::Identity *>(id)->sign(data, len, signature, signatureBufferLength);
+}
+
+int ZT_Identity_verify(const ZT_Identity *id, const void *data, unsigned int len, const void *signature, unsigned int sigLen)
+{
+	if ((!id) || (!signature) || (!sigLen))
+		return 0;
+	return reinterpret_cast<const ZeroTier::Identity *>(id)->verify(data, len, signature, sigLen) ? 1 : 0;
+}
+
+enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id)
+{
+	if (!id)
+		return (ZT_IdentityType)0;
+	return (enum ZT_IdentityType)reinterpret_cast<const ZeroTier::Identity *>(id)->type();
+}
+
+char *ZT_Identity_toString(const ZT_Identity *id, char *buf, int capacity, int includePrivate)
+{
+	if ((!id) || (!buf) || (capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH))
+		return nullptr;
+	reinterpret_cast<const ZeroTier::Identity *>(id)->toString(includePrivate != 0, buf);
+	return buf;
+}
+
+int ZT_Identity_hasPrivate(const ZT_Identity *id)
+{
+	if (!id)
+		return 0;
+	return reinterpret_cast<const ZeroTier::Identity *>(id)->hasPrivate() ? 1 : 0;
+}
+
+uint64_t ZT_Identity_address(const ZT_Identity *id)
+{
+	if (!id)
+		return 0;
+	return reinterpret_cast<const ZeroTier::Identity *>(id)->address();
+}
+
+const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id)
+{
+	if (!id)
+		return nullptr;
+	return &(reinterpret_cast<const ZeroTier::Identity *>(id)->fingerprint());
+}
+
+void ZT_Identity_delete(ZT_Identity *id)
+{
+	if (id)
+		delete reinterpret_cast<ZeroTier::Identity *>(id);
+}
+
+/********************************************************************************************************************/
+
+int ZT_Certificate_newSubjectUniqueId(
+	enum ZT_CertificateUniqueIdType type,
+	void *uniqueId,
+	int *uniqueIdSize,
+	void *uniqueIdPrivate,
+	int *uniqueIdPrivateSize)
+{
+	try {
+		switch (type) {
+			case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
+				if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
+					return ZT_RESULT_ERROR_BAD_PARAMETER;
+				*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
+				*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
+				ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
+				return ZT_RESULT_OK;
+		}
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
+}
+
+int ZT_Certificate_newCSR(
+	const ZT_Certificate_Subject *subject,
+	const void *uniqueId,
+	int uniqueIdSize,
+	const void *uniqueIdPrivate,
+	int uniqueIdPrivateSize,
+	void *csr,
+	int *csrSize)
+{
+	try {
+		if (!subject)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, uniqueId, uniqueIdSize, uniqueIdPrivate, uniqueIdPrivateSize));
+		if ((int)csrV.size() > *csrSize)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
+		*csrSize = (int)csrV.size();
+		return ZT_RESULT_OK;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
+}
+
+int ZT_Certificate_sign(
+	const ZT_Certificate *cert,
+	const ZT_Identity *signer,
+	void *signedCert,
+	int *signedCertSize)
+{
+	try {
+		if (!cert)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Certificate c(*cert);
+		if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
+			return ZT_RESULT_ERROR_INTERNAL;
+
+		const ZeroTier::Vector< uint8_t > enc(c.encode());
+		if ((int)enc.size() > *signedCertSize)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
+		*signedCertSize = (int)enc.size();
+
+		return ZT_RESULT_OK;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_CertificateError ZT_Certificate_decode(
+	const ZT_Certificate **decodedCert,
+	const void *cert,
+	int certSize,
+	int verify)
+{
+	try {
+		if ((!decodedCert) || (!cert) || (certSize <= 0))
+			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+		*decodedCert = nullptr;
+		ZeroTier::Certificate *const c = new ZeroTier::Certificate();
+		if (!c->decode(cert, certSize)) {
+			delete c;
+			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+		}
+		if (verify) {
+			const ZT_CertificateError err = c->verify();
+			if (err != ZT_CERTIFICATE_ERROR_NONE) {
+				delete c;
+				return err;
+			}
+		}
+		*decodedCert = c;
+		return ZT_CERTIFICATE_ERROR_NONE;
+	} catch (...) {
+		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+	}
+}
+
+int ZT_Certificate_encode(
+	const ZT_Certificate *cert,
+	void *encoded,
+	int *encodedSize)
+{
+	try {
+		if ((!cert) || (!encoded) || (!encodedSize))
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Certificate c(*cert);
+		ZeroTier::Vector< uint8_t > enc(c.encode());
+		if ((int)enc.size() > *encodedSize)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size());
+		*encodedSize = (int)enc.size();
+		return ZT_RESULT_OK;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
+}
+
+enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
+{
+	try {
+		if (!cert)
+			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+		return ZeroTier::Certificate(*cert).verify();
+	} catch (...) {
+		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+	}
+}
+
+const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert)
+{
+	try {
+		if (!cert)
+			return nullptr;
+		return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert));
+	} catch (...) {
+		return nullptr;
+	}
+}
+
+void ZT_Certificate_delete(const ZT_Certificate *cert)
+{
+	try {
+		if (cert)
+			delete (const ZeroTier::Certificate *)(cert);
+	} catch (...) {}
+}
+
+/********************************************************************************************************************/
+
+} // extern "C"

+ 1 - 0
core/CMakeLists.txt

@@ -63,6 +63,7 @@ set(core_src
 	AES.cpp
 	AES.cpp
 	Buf.cpp
 	Buf.cpp
 	C25519.cpp
 	C25519.cpp
+	CAPI.cpp
 	CapabilityCredential.cpp
 	CapabilityCredential.cpp
 	Certificate.cpp
 	Certificate.cpp
 	Defaults.cpp
 	Defaults.cpp

+ 0 - 154
core/Certificate.cpp

@@ -663,157 +663,3 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
 }
 }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier
-
-extern "C" {
-
-int ZT_Certificate_newSubjectUniqueId(
-	enum ZT_CertificateUniqueIdType type,
-	void *uniqueId,
-	int *uniqueIdSize,
-	void *uniqueIdPrivate,
-	int *uniqueIdPrivateSize)
-{
-	try {
-		switch (type) {
-			case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
-				if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
-					return ZT_RESULT_ERROR_BAD_PARAMETER;
-				*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
-				*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
-				ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
-				return ZT_RESULT_OK;
-		}
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	} catch (...) {
-		return ZT_RESULT_FATAL_ERROR_INTERNAL;
-	}
-}
-
-int ZT_Certificate_newCSR(
-	const ZT_Certificate_Subject *subject,
-	const void *uniqueId,
-	int uniqueIdSize,
-	const void *uniqueIdPrivate,
-	int uniqueIdPrivateSize,
-	void *csr,
-	int *csrSize)
-{
-	try {
-		if (!subject)
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, uniqueId, uniqueIdSize, uniqueIdPrivate, uniqueIdPrivateSize));
-		if ((int)csrV.size() > *csrSize)
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
-		*csrSize = (int)csrV.size();
-		return ZT_RESULT_OK;
-	} catch (...) {
-		return ZT_RESULT_FATAL_ERROR_INTERNAL;
-	}
-}
-
-int ZT_Certificate_sign(
-	const ZT_Certificate *cert,
-	const ZT_Identity *signer,
-	void *signedCert,
-	int *signedCertSize)
-{
-	try {
-		if (!cert)
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		ZeroTier::Certificate c(*cert);
-		if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
-			return ZT_RESULT_ERROR_INTERNAL;
-
-		const ZeroTier::Vector< uint8_t > enc(c.encode());
-		if ((int)enc.size() > *signedCertSize)
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
-		*signedCertSize = (int)enc.size();
-
-		return ZT_RESULT_OK;
-	} catch (...) {
-		return ZT_RESULT_FATAL_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_CertificateError ZT_Certificate_decode(
-	const ZT_Certificate **decodedCert,
-	const void *cert,
-	int certSize,
-	int verify)
-{
-	try {
-		if ((!decodedCert) || (!cert) || (certSize <= 0))
-			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-		*decodedCert = nullptr;
-		ZeroTier::Certificate *const c = new ZeroTier::Certificate();
-		if (!c->decode(cert, certSize)) {
-			delete c;
-			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-		}
-		if (verify) {
-			const ZT_CertificateError err = c->verify();
-			if (err != ZT_CERTIFICATE_ERROR_NONE) {
-				delete c;
-				return err;
-			}
-		}
-		*decodedCert = c;
-		return ZT_CERTIFICATE_ERROR_NONE;
-	} catch (...) {
-		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-	}
-}
-
-int ZT_Certificate_encode(
-	const ZT_Certificate *cert,
-	void *encoded,
-	int *encodedSize)
-{
-	try {
-		if ((!cert) || (!encoded) || (!encodedSize))
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		ZeroTier::Certificate c(*cert);
-		ZeroTier::Vector< uint8_t > enc(c.encode());
-		if ((int)enc.size() > *encodedSize)
-			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size());
-		*encodedSize = (int)enc.size();
-		return ZT_RESULT_OK;
-	} catch (...) {
-		return ZT_RESULT_FATAL_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
-{
-	try {
-		if (!cert)
-			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-		return ZeroTier::Certificate(*cert).verify();
-	} catch (...) {
-		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-	}
-}
-
-const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert)
-{
-	try {
-		if (!cert)
-			return nullptr;
-		return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert));
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-void ZT_Certificate_delete(const ZT_Certificate *cert)
-{
-	try {
-		if (cert)
-			delete (const ZeroTier::Certificate *)(cert);
-	} catch (...) {}
-}
-
-}

+ 0 - 98
core/Identity.cpp

@@ -542,101 +542,3 @@ void Identity::m_computeHash()
 }
 }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier
-
-extern "C" {
-
-ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type)
-{
-	if ((type != ZT_IDENTITY_TYPE_C25519) && (type != ZT_IDENTITY_TYPE_P384))
-		return nullptr;
-	try {
-		ZeroTier::Identity *const id = new ZeroTier::Identity();
-		id->generate((ZeroTier::Identity::Type)type);
-		return reinterpret_cast<ZT_Identity *>(id);
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-ZT_Identity *ZT_Identity_fromString(const char *idStr)
-{
-	if (!idStr)
-		return nullptr;
-	try {
-		ZeroTier::Identity *const id = new ZeroTier::Identity();
-		if (!id->fromString(idStr)) {
-			delete id;
-			return nullptr;
-		}
-		return reinterpret_cast<ZT_Identity *>(id);
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-int ZT_Identity_validate(const ZT_Identity *id)
-{
-	if (!id)
-		return 0;
-	return reinterpret_cast<const ZeroTier::Identity *>(id)->locallyValidate() ? 1 : 0;
-}
-
-unsigned int ZT_Identity_sign(const ZT_Identity *id, const void *data, unsigned int len, void *signature, unsigned int signatureBufferLength)
-{
-	if (!id)
-		return 0;
-	if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE)
-		return 0;
-	return reinterpret_cast<const ZeroTier::Identity *>(id)->sign(data, len, signature, signatureBufferLength);
-}
-
-int ZT_Identity_verify(const ZT_Identity *id, const void *data, unsigned int len, const void *signature, unsigned int sigLen)
-{
-	if ((!id) || (!signature) || (!sigLen))
-		return 0;
-	return reinterpret_cast<const ZeroTier::Identity *>(id)->verify(data, len, signature, sigLen) ? 1 : 0;
-}
-
-enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id)
-{
-	if (!id)
-		return (ZT_IdentityType)0;
-	return (enum ZT_IdentityType)reinterpret_cast<const ZeroTier::Identity *>(id)->type();
-}
-
-char *ZT_Identity_toString(const ZT_Identity *id, char *buf, int capacity, int includePrivate)
-{
-	if ((!id) || (!buf) || (capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH))
-		return nullptr;
-	reinterpret_cast<const ZeroTier::Identity *>(id)->toString(includePrivate != 0, buf);
-	return buf;
-}
-
-int ZT_Identity_hasPrivate(const ZT_Identity *id)
-{
-	if (!id)
-		return 0;
-	return reinterpret_cast<const ZeroTier::Identity *>(id)->hasPrivate() ? 1 : 0;
-}
-
-uint64_t ZT_Identity_address(const ZT_Identity *id)
-{
-	if (!id)
-		return 0;
-	return reinterpret_cast<const ZeroTier::Identity *>(id)->address();
-}
-
-const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id)
-{
-	if (!id)
-		return nullptr;
-	return &(reinterpret_cast<const ZeroTier::Identity *>(id)->fingerprint());
-}
-
-ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
-{
-	if (id)
-		delete reinterpret_cast<ZeroTier::Identity *>(id);
-}
-
-}

+ 0 - 119
core/Locator.cpp

@@ -204,122 +204,3 @@ void Locator::m_sortEndpoints() noexcept
 { std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); }
 { std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier
-
-extern "C" {
-
-ZT_Locator *ZT_Locator_create(
-	int64_t ts,
-	const ZT_Endpoint *endpoints,
-	const ZT_EndpointAttributes *endpointAttributes, // TODO: not used yet
-	unsigned int endpointCount,
-	const ZT_Identity *signer)
-{
-	try {
-		if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
-			return nullptr;
-		ZeroTier::Locator *loc = new ZeroTier::Locator();
-		for (unsigned int i = 0;i < endpointCount;++i)
-			loc->add(reinterpret_cast< const ZeroTier::Endpoint * >(endpoints)[i], ZeroTier::Locator::EndpointAttributes::DEFAULT);
-		if (!loc->sign(ts, *reinterpret_cast< const ZeroTier::Identity * >(signer))) {
-			delete loc;
-			return nullptr;
-		}
-		return reinterpret_cast<ZT_Locator *>(loc);
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-ZT_Locator *ZT_Locator_fromString(const char *str)
-{
-	try {
-		if (!str)
-			return nullptr;
-		ZeroTier::Locator *loc = new ZeroTier::Locator();
-		if (!loc->fromString(str)) {
-			delete loc;
-			return nullptr;
-		}
-		return reinterpret_cast<ZT_Locator *>(loc);
-	} catch ( ... ) {
-		return nullptr;
-	}
-}
-
-ZT_Locator *ZT_Locator_unmarshal(
-	const void *data,
-	unsigned int len)
-{
-	try {
-		if ((!data) || (len == 0))
-			return nullptr;
-		ZeroTier::Locator *loc = new ZeroTier::Locator();
-		if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data), (int) len) <= 0) {
-			delete loc;
-			return nullptr;
-		}
-		return reinterpret_cast<ZT_Locator *>(loc);
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-int ZT_Locator_marshal(const ZT_Locator *loc, void *buf, unsigned int bufSize)
-{
-	if ((!loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX))
-		return -1;
-	return reinterpret_cast<const ZeroTier::Locator *>(loc)->marshal(reinterpret_cast<uint8_t *>(buf), (int) bufSize);
-}
-
-char *ZT_Locator_toString(
-	const ZT_Locator *loc,
-	char *buf,
-	int capacity)
-{
-	if ((!loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX))
-		return nullptr;
-	return reinterpret_cast<const ZeroTier::Locator *>(loc)->toString(buf);
-}
-
-const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc)
-{
-	if (!loc)
-		return nullptr;
-	return (ZT_Fingerprint *) (&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
-}
-
-int64_t ZT_Locator_timestamp(const ZT_Locator *loc)
-{
-	if (!loc)
-		return 0;
-	return reinterpret_cast<const ZeroTier::Locator *>(loc)->timestamp();
-}
-
-unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc)
-{
-	return (loc) ? (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()) : 0;
-}
-
-const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc, const unsigned int ep)
-{
-	if (!loc)
-		return nullptr;
-	if (ep >= (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()))
-		return nullptr;
-	return reinterpret_cast<const ZT_Endpoint *>(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints()[ep]));
-}
-
-int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer)
-{
-	if ((!loc) || (!signer))
-		return 0;
-	return reinterpret_cast<const ZeroTier::Locator *>(loc)->verify(*reinterpret_cast<const ZeroTier::Identity *>(signer)) ? 1 : 0;
-}
-
-void ZT_Locator_delete(ZT_Locator *loc)
-{
-	if (loc)
-		delete reinterpret_cast<ZeroTier::Locator *>(loc);
-}
-
-} // C API functions

+ 2 - 0
core/MAC.hpp

@@ -264,6 +264,8 @@ private:
 	uint64_t m_mac;
 	uint64_t m_mac;
 };
 };
 
 
+static_assert(sizeof(MAC) == sizeof(uint64_t),"MAC contains unnecessary padding");
+
 } // namespace ZeroTier
 } // namespace ZeroTier
 
 
 #endif
 #endif

+ 0 - 317
core/Node.cpp

@@ -840,320 +840,3 @@ void Node::ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address &d
 }
 }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier
-
-// C API --------------------------------------------------------------------------------------------------------------
-
-extern "C" {
-
-// These macros make the idiom of passing buffers to outside code via the API work properly even
-// if the first address of Buf does not overlap with its data field, since the C++ standard does
-// not absolutely guarantee this.
-#define _ZT_PTRTOBUF(p) ((ZeroTier::Buf *)( ((uintptr_t)(p)) - ((uintptr_t)&(((ZeroTier::Buf *)0)->unsafeData[0])) ))
-#define _ZT_BUFTOPTR(b) ((void *)(&((b)->unsafeData[0])))
-
-void *ZT_getBuffer()
-{
-	// When external code requests a Buf, grab one from the pool (or freshly allocated)
-	// and return it with its reference count left at zero. It's the responsibility of
-	// external code to bring it back via freeBuffer() or one of the processX() calls.
-	// When this occurs it's either sent back to the pool with Buf's delete operator or
-	// wrapped in a SharedPtr<> to be passed into the core.
-	try {
-		return _ZT_BUFTOPTR(new ZeroTier::Buf());
-	} catch (...) {
-		return nullptr; // can only happen on out of memory condition
-	}
-}
-
-void ZT_freeBuffer(void *b)
-{
-	if (b)
-		delete _ZT_PTRTOBUF(b);
-}
-
-struct p_queryResultBase
-{
-	void (*freeFunction)(const void *);
-};
-
-void ZT_freeQueryResult(const void *qr)
-{
-	if ((qr) && (reinterpret_cast<const p_queryResultBase *>(qr)->freeFunction))
-		reinterpret_cast<const p_queryResultBase *>(qr)->freeFunction(qr);
-}
-
-enum ZT_ResultCode ZT_Node_new(ZT_Node **node, void *uptr, void *tptr, const struct ZT_Node_Callbacks *callbacks, int64_t now)
-{
-	*node = (ZT_Node *)0;
-	try {
-		*node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(uptr, tptr, callbacks, now));
-		return ZT_RESULT_OK;
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (std::runtime_error &exc) {
-		return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-void ZT_Node_delete(ZT_Node *node, void *tPtr)
-{
-	try {
-		reinterpret_cast<ZeroTier::Node *>(node)->shutdown(tPtr);
-		delete (reinterpret_cast<ZeroTier::Node *>(node));
-	} catch (...) {}
-}
-
-enum ZT_ResultCode ZT_Node_processWirePacket(
-	ZT_Node *node,
-	void *tptr,
-	int64_t now,
-	int64_t localSocket,
-	const struct sockaddr_storage *remoteAddress,
-	const void *packetData,
-	unsigned int packetLength,
-	int isZtBuffer,
-	volatile int64_t *nextBackgroundTaskDeadline)
-{
-	try {
-		ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? _ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK));
-		return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr, now, localSocket, remoteAddress, buf, packetLength, nextBackgroundTaskDeadline);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		// "OK" since invalid packets are simply dropped, but the system is still up.
-		// We should never make it here, but if we did that would be the interpretation.
-		return ZT_RESULT_OK;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
-	ZT_Node *node,
-	void *tptr,
-	int64_t now,
-	uint64_t nwid,
-	uint64_t sourceMac,
-	uint64_t destMac,
-	unsigned int etherType,
-	unsigned int vlanId,
-	const void *frameData,
-	unsigned int frameLength,
-	int isZtBuffer,
-	volatile int64_t *nextBackgroundTaskDeadline)
-{
-	try {
-		ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? _ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData, frameLength & ZT_BUF_MEM_MASK));
-		return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(tptr, now, nwid, sourceMac, destMac, etherType, vlanId, buf, frameLength, nextBackgroundTaskDeadline);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node, void *tptr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(tptr, now, nextBackgroundTaskDeadline);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_join(ZT_Node *node, uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, void *tptr)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->join(nwid, controllerFingerprint, uptr, tptr);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_leave(ZT_Node *node, uint64_t nwid, void **uptr, void *tptr)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid, uptr, tptr);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node, void *tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->multicastSubscribe(tptr, nwid, multicastGroup, multicastAdi);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->multicastUnsubscribe(nwid, multicastGroup, multicastAdi);
-	} catch (std::bad_alloc &exc) {
-		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-uint64_t ZT_Node_address(ZT_Node *node)
-{
-	return reinterpret_cast<ZeroTier::Node *>(node)->address();
-}
-
-const ZT_Identity *ZT_Node_identity(ZT_Node *node)
-{
-	return (const ZT_Identity *)(&(reinterpret_cast<ZeroTier::Node *>(node)->identity()));
-}
-
-void ZT_Node_status(ZT_Node *node, ZT_NodeStatus *status)
-{
-	try {
-		reinterpret_cast<ZeroTier::Node *>(node)->status(status);
-	} catch (...) {}
-}
-
-ZT_PeerList *ZT_Node_peers(ZT_Node *node)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->peers();
-	} catch (...) {
-		return (ZT_PeerList *)0;
-	}
-}
-
-ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node, uint64_t nwid)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->networkConfig(nwid);
-	} catch (...) {
-		return (ZT_VirtualNetworkConfig *)0;
-	}
-}
-
-ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->networks();
-	} catch (...) {
-		return (ZT_VirtualNetworkList *)0;
-	}
-}
-
-int ZT_Node_tryPeer(
-	ZT_Node *node,
-	void *tptr,
-	const ZT_Fingerprint *fp,
-	const ZT_Endpoint *endpoint,
-	int retries)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->tryPeer(tptr, fp, endpoint, retries);
-	} catch (...) {
-		return 0;
-	}
-}
-
-enum ZT_CertificateError ZT_Node_addCertificate(
-	ZT_Node *node,
-	void *tptr,
-	int64_t now,
-	unsigned int localTrust,
-	const ZT_Certificate *cert,
-	const void *certData,
-	unsigned int certSize)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->addCertificate(tptr, now, localTrust, cert, certData, certSize);
-	} catch (...) {
-		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
-	}
-}
-
-ZT_SDK_API enum ZT_ResultCode ZT_Node_deleteCertificate(
-	ZT_Node *node,
-	void *tptr,
-	const void *serialNo)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->deleteCertificate(tptr, serialNo);
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates(ZT_Node *node)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->listCertificates();
-	} catch (...) {
-		return nullptr;
-	}
-}
-
-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_setInterfaceAddresses(ZT_Node *node, const ZT_InterfaceAddress *addrs, unsigned int addrCount)
-{
-	try {
-		reinterpret_cast<ZeroTier::Node *>(node)->setInterfaceAddresses(addrs, addrCount);
-	} catch (...) {}
-}
-
-enum ZT_ResultCode ZT_Node_addPeer(
-	ZT_Node *node,
-	void *tptr,
-	const ZT_Identity *id)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->addPeer(tptr, id);
-	} catch (...) {
-		return ZT_RESULT_ERROR_INTERNAL;
-	}
-}
-
-int ZT_Node_sendUserMessage(ZT_Node *node, void *tptr, uint64_t dest, uint64_t typeId, const void *data, unsigned int len)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->sendUserMessage(tptr, dest, typeId, data, len);
-	} catch (...) {
-		return 0;
-	}
-}
-
-void ZT_Node_setController(ZT_Node *node, void *networkControllerInstance)
-{
-	try {
-		reinterpret_cast<ZeroTier::Node *>(node)->setController(networkControllerInstance);
-	} catch (...) {}
-}
-
-void ZT_version(int *major, int *minor, int *revision, int *build)
-{
-	if (major)
-		*major = ZEROTIER_VERSION_MAJOR;
-	if (minor)
-		*minor = ZEROTIER_VERSION_MINOR;
-	if (revision)
-		*revision = ZEROTIER_VERSION_REVISION;
-	if (build)
-		*build = ZEROTIER_VERSION_BUILD;
-}
-
-} // extern "C"

+ 15 - 10
core/OS.hpp

@@ -115,14 +115,6 @@
 #include <mmintrin.h>
 #include <mmintrin.h>
 #endif
 #endif
 
 
-#if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON))
-#ifndef ZT_ARCH_ARM_HAS_NEON
-#define ZT_ARCH_ARM_HAS_NEON 1
-#endif
-#include <arm_neon.h>
-/*#include <arm_acle.h>*/
-#endif
-
 #if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)
 #if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)
 #define ZT_ARCH_X86 1
 #define ZT_ARCH_X86 1
 #endif
 #endif
@@ -133,6 +125,20 @@
 #endif
 #endif
 #endif
 #endif
 
 
+#if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON))
+#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
+#ifdef ZT_ARCH_ARM_HAS_NEON
+#undef ZT_ARCH_ARM_HAS_NEON
+#endif
+#else
+#ifndef ZT_ARCH_ARM_HAS_NEON
+#define ZT_ARCH_ARM_HAS_NEON 1
+#endif
+#include <arm_neon.h>
+/*#include <arm_acle.h>*/
+#endif
+#endif
+
 #if defined(__SIZEOF_INT128__) || ((defined(ZT_ARCH_X64) || defined(__aarch64__)) && defined(__GNUC__))
 #if defined(__SIZEOF_INT128__) || ((defined(ZT_ARCH_X64) || defined(__aarch64__)) && defined(__GNUC__))
 #ifdef __SIZEOF_INT128__
 #ifdef __SIZEOF_INT128__
 #define ZT_HAVE_UINT128 1
 #define ZT_HAVE_UINT128 1
@@ -216,10 +222,9 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
 #endif
 #endif
 #endif
 #endif
 
 
-// Macro to print very verbose tracing information to standard error.
-#define ZT_VA_ARGS(...) , ##__VA_ARGS__
 #define ZT_DEBUG_SPEW
 #define ZT_DEBUG_SPEW
 #ifdef ZT_DEBUG_SPEW
 #ifdef ZT_DEBUG_SPEW
+#define ZT_VA_ARGS(...) , ##__VA_ARGS__
 #define ZT_SPEW(f,...) fprintf(stderr,"%s:%d(%s): " f ZT_EOL_S,__FILE__,__LINE__,__FUNCTION__ ZT_VA_ARGS(__VA_ARGS__))
 #define ZT_SPEW(f,...) fprintf(stderr,"%s:%d(%s): " f ZT_EOL_S,__FILE__,__LINE__,__FUNCTION__ ZT_VA_ARGS(__VA_ARGS__))
 #else
 #else
 #define ZT_SPEW(f,...)
 #define ZT_SPEW(f,...)

+ 0 - 1
core/Topology.hpp

@@ -194,7 +194,6 @@ private:
 		SharedPtr< const Certificate > certificate;
 		SharedPtr< const Certificate > certificate;
 		unsigned int localTrust;
 		unsigned int localTrust;
 	};
 	};
-
 	Map< SHA384Hash, p_CertEntry > m_certs;
 	Map< SHA384Hash, p_CertEntry > m_certs;
 	Map< SHA384Hash, p_CertEntry > m_certsBySubjectUniqueID;
 	Map< SHA384Hash, p_CertEntry > m_certsBySubjectUniqueID;
 	Map< Fingerprint, Map< SharedPtr< const Certificate >, unsigned int > > m_certsBySubjectIdentity;
 	Map< Fingerprint, Map< SharedPtr< const Certificate >, unsigned int > > m_certsBySubjectIdentity;

+ 28 - 14
core/Utils.cpp

@@ -38,9 +38,21 @@ namespace ZeroTier {
 
 
 namespace Utils {
 namespace Utils {
 
 
-#ifdef ZT_ARCH_ARM_HAS_NEON
+#ifdef ZT_ARCH_ARM_HAS_NEON /****************************************************************************************/
 ARMCapabilities::ARMCapabilities() noexcept
 ARMCapabilities::ARMCapabilities() noexcept
 {
 {
+
+#ifdef __APPLE__
+
+	this->aes = true;
+	this->crc32 = true;
+	this->pmull = true;
+	this->sha1 = true;
+	this->sha2 = true;
+
+#else
+
+#ifdef __LINUX__
 #ifdef HWCAP2_AES
 #ifdef HWCAP2_AES
 	if (sizeof(void *) == 4) {
 	if (sizeof(void *) == 4) {
 		const long hwcaps2 = getauxval(AT_HWCAP2);
 		const long hwcaps2 = getauxval(AT_HWCAP2);
@@ -60,13 +72,16 @@ ARMCapabilities::ARMCapabilities() noexcept
 #ifdef HWCAP2_AES
 #ifdef HWCAP2_AES
 	}
 	}
 #endif
 #endif
-}
+#endif
 
 
-const ARMCapabilities ARMCAP;
 #endif
 #endif
 
 
-#ifdef ZT_ARCH_X64
+}
 
 
+const ARMCapabilities ARMCAP;
+#endif /*************************************************************************************************************/
+
+#ifdef ZT_ARCH_X64 /*************************************************************************************************/
 CPUIDRegisters::CPUIDRegisters() noexcept
 CPUIDRegisters::CPUIDRegisters() noexcept
 {
 {
 	uint32_t eax, ebx, ecx, edx;
 	uint32_t eax, ebx, ecx, edx;
@@ -113,7 +128,7 @@ CPUIDRegisters::CPUIDRegisters() noexcept
 }
 }
 
 
 const CPUIDRegisters CPUID;
 const CPUIDRegisters CPUID;
-#endif
+#endif /*************************************************************************************************************/
 
 
 const std::bad_alloc BadAllocException;
 const std::bad_alloc BadAllocException;
 const std::out_of_range OutOfRangeException("access out of range");
 const std::out_of_range OutOfRangeException("access out of range");
@@ -131,19 +146,18 @@ bool secureEq(const void *a, const void *b, unsigned int len) noexcept
 
 
 void burn(volatile void *ptr, unsigned int len)
 void burn(volatile void *ptr, unsigned int len)
 {
 {
+	static volatile uintptr_t foo = 0;
 	Utils::zero((void *)ptr, len);
 	Utils::zero((void *)ptr, len);
-	// This line is present to force the compiler not to optimize out the memory
-	// zeroing operation above, as burn() is used to erase secrets and other
-	// sensitive data.
-	if ((reinterpret_cast<volatile uint8_t *>(ptr)[0] | reinterpret_cast<volatile uint8_t *>(ptr)[len-1]) != 0)
-		burn(ptr, len);
+	// Force compiler not to optimize this function out by taking a volatile
+	// parameter and also updating a volatile variable.
+	foo += (uintptr_t)len ^ (uintptr_t)reinterpret_cast<volatile uint8_t *>(ptr)[0];
 }
 }
 
 
-static unsigned long _Utils_itoa(unsigned long n, char *s)
+static unsigned long s_decimalRecursive(unsigned long n, char *s)
 {
 {
 	if (n == 0)
 	if (n == 0)
 		return 0;
 		return 0;
-	unsigned long pos = _Utils_itoa(n / 10, s);
+	unsigned long pos = s_decimalRecursive(n / 10, s);
 	if (pos >= 22) // sanity check,should be impossible
 	if (pos >= 22) // sanity check,should be impossible
 		pos = 22;
 		pos = 22;
 	s[pos] = (char)('0' + (n % 10));
 	s[pos] = (char)('0' + (n % 10));
@@ -157,7 +171,7 @@ char *decimal(unsigned long n, char s[24]) noexcept
 		s[1] = (char)0;
 		s[1] = (char)0;
 		return s;
 		return s;
 	}
 	}
-	s[_Utils_itoa(n, s)] = (char)0;
+	s[s_decimalRecursive(n, s)] = (char)0;
 	return s;
 	return s;
 }
 }
 
 
@@ -353,7 +367,7 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
 
 
 uint64_t getSecureRandomU64() noexcept
 uint64_t getSecureRandomU64() noexcept
 {
 {
-	uint64_t tmp = 0;
+	uint64_t tmp;
 	getSecureRandom(&tmp, sizeof(tmp));
 	getSecureRandom(&tmp, sizeof(tmp));
 	return tmp;
 	return tmp;
 }
 }