Merge refactored dev into master

This commit is contained in:
Joseph Henry
2021-03-12 20:32:08 -08:00
164 changed files with 3852 additions and 6273 deletions

View File

@@ -14,7 +14,7 @@
#ifndef ZT_CENTRAL_H
#define ZT_CENTRAL_H
#ifdef CENTRAL_API
#ifdef ZTS_ENABLE_CENTRAL_API
#include <stdio.h>
#include <curl/curl.h>

View File

@@ -25,15 +25,16 @@
#include "Mutex.hpp"
#include "OSUtils.hpp"
#include "ZeroTierSockets.h"
#include "Debug.hpp"
#include "NodeService.hpp"
#include "VirtualTap.hpp"
#include "Events.hpp"
#include "ZeroTierSockets.h"
#include "Signals.hpp"
using namespace ZeroTier;
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#include <jni.h>
#endif
@@ -46,13 +47,20 @@ namespace ZeroTier
{
extern NodeService *service;
extern Mutex serviceLock;
extern void (*_userEventCallbackFunc)(void *);
#ifdef ZTS_ENABLE_PYTHON
#endif
#ifdef ZTS_ENABLE_PINVOKE
extern void (*_userEventCallback)(void *);
#endif
#ifdef ZTS_C_API_ONLY
extern void (*_userEventCallback)(void *);
#endif
extern uint8_t allowNetworkCaching;
extern uint8_t allowPeerCaching;
extern uint8_t allowLocalConf;
extern uint8_t disableLocalStorage; // Off by default
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
// References to JNI objects and VM kept for future callbacks
JavaVM *jvm = NULL;
jobject objRef = NULL;
@@ -110,10 +118,15 @@ int zts_get_node_identity(char *key_pair_str, uint16_t *key_buf_len)
}
// TODO: This logic should be further generalized in the next API redesign
#ifdef ZTS_PINVOKE
#ifdef ZTS_ENABLE_PYTHON
int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
PythonDirectorCallbackClass *callback, uint16_t port)
#endif
#ifdef ZTS_ENABLE_PINVOKE
int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
CppCallback callback, uint16_t port)
#else
#endif
#ifdef ZTS_C_API_ONLY
int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
void (*callback)(void *), uint16_t port)
#endif
@@ -122,6 +135,9 @@ int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
return ZTS_ERR_ARG;
}
Mutex::Lock _l(serviceLock);
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
_install_signal_handlers();
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
_lwip_driver_init();
if (service || _getState(ZTS_STATE_NODE_RUNNING)) {
// Service is already initialized
@@ -132,11 +148,7 @@ int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
// an application restart is required now
return ZTS_ERR_SERVICE;
}
#ifdef SDK_JNI
_userEventCallbackFunc = callback;
#else
_userEventCallbackFunc = callback;
#endif
_userEventCallback = callback;
if (!_isCallbackRegistered()) {
// Must have a callback
return ZTS_ERR_ARG;
@@ -231,13 +243,20 @@ int zts_disable_local_storage(uint8_t disabled)
return ZTS_ERR_SERVICE;
}
#ifdef ZTS_PINVOKE
#ifdef ZTS_ENABLE_PYTHON
int zts_start(const char *path, PythonDirectorCallbackClass *callback, uint16_t port)
#endif
#ifdef ZTS_ENABLE_PINVOKE
int zts_start(const char *path, CppCallback callback, uint16_t port)
#else
#endif
#ifdef ZTS_C_API_ONLY
int zts_start(const char *path, void (*callback)(void *), uint16_t port)
#endif
{
Mutex::Lock _l(serviceLock);
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
_install_signal_handlers();
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
_lwip_driver_init();
if (service || _getState(ZTS_STATE_NODE_RUNNING)) {
// Service is already initialized
@@ -248,11 +267,7 @@ int zts_start(const char *path, void (*callback)(void *), uint16_t port)
// an application restart is required now
return ZTS_ERR_SERVICE;
}
#ifdef SDK_JNI
_userEventCallbackFunc = callback;
#else
_userEventCallbackFunc = callback;
#endif
_userEventCallback = callback;
if (!_isCallbackRegistered()) {
// Must have a callback
return ZTS_ERR_ARG;
@@ -300,7 +315,7 @@ int zts_start(const char *path, void (*callback)(void *), uint16_t port)
return retval;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_start(
JNIEnv *env, jobject thisObj, jstring path, jobject callback, jint port)
{
@@ -344,7 +359,7 @@ int zts_stop()
}
return ZTS_ERR_SERVICE;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_stop(
JNIEnv *env, jobject thisObj)
{
@@ -357,11 +372,8 @@ int zts_restart()
{
serviceLock.lock();
// Store callback references
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
static jmethodID _tmpUserCallbackMethodRef = _userCallbackMethodRef;
#else
void (*_tmpUserEventCallbackFunc)(void *);
_tmpUserEventCallbackFunc = _userEventCallbackFunc;
#endif
int userProvidedPort = 0;
std::string userProvidedPath;
@@ -388,15 +400,14 @@ int zts_restart()
}
/* Some of the logic in Java_com_zerotier_libzt_ZeroTier_start
is replicated here */
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
_userCallbackMethodRef = _tmpUserCallbackMethodRef;
return zts_start(userProvidedPath.c_str(), NULL, userProvidedPort);
#else
return ZTS_ERR_OK;
//return zts_start(userProvidedPath.c_str(), _tmpUserEventCallbackFunc, userProvidedPort);
return ZTS_ERR_OK;
#endif
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_restart(
JNIEnv *env, jobject thisObj)
{
@@ -415,7 +426,7 @@ int zts_free()
_lwip_driver_shutdown();
return err;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_free(
JNIEnv *env, jobject thisObj)
{
@@ -423,7 +434,7 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_free(
}
#endif
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
/*
* Called from Java, saves a static reference to the VM so it can be used
* later to call a user-specified callback method from C.
@@ -431,7 +442,7 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_free(
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_init(
JNIEnv *env, jobject thisObj)
{
jint rs = env->GetJavaVM(&jvm);
jint rs = env->GetJavaVM(&jvm);
return rs != JNI_OK ? ZTS_ERR_GENERAL : ZTS_ERR_OK;
}
#endif
@@ -447,7 +458,7 @@ int zts_join(const uint64_t networkId)
}
return ZTS_ERR_OK;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_join(
JNIEnv *env, jobject thisObj, jlong networkId)
{
@@ -466,7 +477,7 @@ int zts_leave(const uint64_t networkId)
}
return ZTS_ERR_OK;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_leave(
JNIEnv *env, jobject thisObj, jlong networkId)
{
@@ -485,7 +496,7 @@ int zts_orbit(uint64_t moonWorldId, uint64_t moonSeed)
}
return ZTS_ERR_OK;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
int zts_deorbit(uint64_t moonWorldId)
@@ -499,7 +510,7 @@ int zts_deorbit(uint64_t moonWorldId)
}
return ZTS_ERR_OK;
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
int zts_get_6plane_addr(struct zts_sockaddr_storage *addr, const uint64_t networkId, const uint64_t nodeId)
@@ -542,14 +553,14 @@ uint64_t zts_generate_adhoc_nwid_from_range(uint16_t startPortOfRange, uint16_t
void zts_delay_ms(long milliseconds)
{
#ifdef __WINDOWS__
Sleep(milliseconds);
Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
#else
usleep(milliseconds * 1000);
usleep(milliseconds * 1000);
#endif
}

View File

@@ -19,7 +19,7 @@
#include "concurrentqueue.h"
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#include <jni.h>
#endif
@@ -40,6 +40,15 @@
#define ROUTE_EVENT_TYPE(code) code >= ZTS_EVENT_ROUTE_ADDED && code <= ZTS_EVENT_ROUTE_REMOVED
#define ADDR_EVENT_TYPE(code) code >= ZTS_EVENT_ADDR_ADDED_IP4 && code <= ZTS_EVENT_ADDR_REMOVED_IP6
#include <execinfo.h>
#include <signal.h>
#ifdef ZTS_ENABLE_PYTHON
#include "Python.h"
PythonDirectorCallbackClass *_userEventCallback = NULL;
void PythonDirectorCallbackClass::on_zerotier_event(struct zts_callback_msg *msg) { }
#endif
namespace ZeroTier {
extern NodeService *service;
@@ -50,7 +59,12 @@ uint8_t _serviceStateFlags;
// Lock to guard access to callback function pointers.
Mutex _callbackLock;
void (*_userEventCallbackFunc)(void *);
#ifdef ZTS_ENABLE_PINVOKE
void (*_userEventCallback)(void *);
#endif
#ifdef ZTS_C_API_ONLY
void (*_userEventCallback)(void *);
#endif
moodycamel::ConcurrentQueue<struct zts_callback_msg*> _callbackMsgQueue;
@@ -100,7 +114,12 @@ void _freeEvent(struct zts_callback_msg *msg)
void _passDequeuedEventToUser(struct zts_callback_msg *msg)
{
bool bShouldStopCallbackThread = (msg->eventCode == ZTS_EVENT_STACK_DOWN);
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_PYTHON
PyGILState_STATE state = PyGILState_Ensure();
_userEventCallback->on_zerotier_event(msg);
PyGILState_Release(state);
#endif
#ifdef ZTS_ENABLE_JAVA
if(_userCallbackMethodRef) {
JNIEnv *env;
#if defined(__ANDROID__)
@@ -121,14 +140,19 @@ void _passDequeuedEventToUser(struct zts_callback_msg *msg)
id = msg->peer ? msg->peer->address : 0;
}
env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->eventCode);
_freeEvent(msg);
}
#else
if (_userEventCallbackFunc) {
_userEventCallbackFunc(msg);
_freeEvent(msg);
#endif // ZTS_ENABLE_JAVA
#ifdef ZTS_ENABLE_PINVOKE
if (_userEventCallback) {
_userEventCallback(msg);
}
#endif
#ifdef ZTS_C_API_ONLY
if (_userEventCallback) {
_userEventCallback(msg);
}
#endif
_freeEvent(msg);
if (bShouldStopCallbackThread) {
/* Ensure last possible callback ZTS_EVENT_STACK_DOWN is
delivered before callback thread is finally stopped. */
@@ -140,10 +164,10 @@ bool _isCallbackRegistered()
{
_callbackLock.lock();
bool retval = false;
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
retval = (jvm && objRef && _userCallbackMethodRef);
#else
retval = _userEventCallbackFunc;
retval = _userEventCallback;
#endif
_callbackLock.unlock();
return retval;
@@ -152,11 +176,11 @@ bool _isCallbackRegistered()
void _clearRegisteredCallback()
{
_callbackLock.lock();
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
objRef = NULL;
_userCallbackMethodRef = NULL;
#else
_userEventCallbackFunc = NULL;
_userEventCallback = NULL;
#endif
_callbackLock.unlock();
}
@@ -237,7 +261,7 @@ void *_runCallbacks(void *thread_id)
}
zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL);
}
#if SDK_JNI
#if ZTS_ENABLE_JAVA
JNIEnv *env;
jint rs = jvm->DetachCurrentThread();
pthread_exit(0);

View File

@@ -29,7 +29,7 @@
#include <BaseTsd.h>
#endif
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#include <jni.h>
#endif
namespace ZeroTier {
@@ -40,7 +40,7 @@ namespace ZeroTier {
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
#define ZTS_STATE_FREE_CALLED 0x10
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
// References to JNI objects and VM kept for future callbacks
extern JavaVM *jvm;
extern jobject objRef;

View File

@@ -51,7 +51,7 @@
#define stat _stat
#endif
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#include <jni.h>
#endif

70
src/Signals.cpp Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (c)2013-2021 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.
*/
/****/
/**
* @file
*
* Custom signal handler
*/
#include "ZeroTierSockets.h"
#include "Signals.hpp"
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
#include <signal.h>
#include <execinfo.h>
#include <cstdlib>
void _signal_handler(int signal)
{
/*
switch(signal)
{
case SIGINT:
fprintf(stderr, "SIGINT\n");
break;
case SIGABRT:
fprintf(stderr, "SIGABRT\n");
break;
case SIGILL:
fprintf(stderr, "SIGILL\n");
break;
case SIGSEGV:
fprintf(stderr, "SIGSEGV\n");
break;
case SIGFPE:
fprintf(stderr, "SIGFPE\n");
break;
case SIGTERM:
default:
fprintf(stderr, "SIGTERM\n");
break;
}
*/
exit(signal);
}
void _install_signal_handlers()
{
signal(SIGINT, &_signal_handler);
/*
signal(SIGABRT, &_signal_handler);
signal(SIGFPE, &_signal_handler);
signal(SIGILL, &_signal_handler);
signal(SIGSEGV, &_signal_handler);
signal(SIGTERM, &_signal_handler);
*/
}
#endif

37
src/Signals.hpp Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (c)2013-2021 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.
*/
/****/
/**
* @file
*
* Custom signal handler
*/
#ifndef SIGNALS_HPP
#define SIGNALS_HPP
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
/**
*
*/
void _signal_handler(int signal);
/**
*
*/
void _install_signal_handlers();
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
#endif // _H

View File

@@ -23,15 +23,14 @@
#include "lwip/stats.h"
#include "ZeroTierSockets.h"
//#include "Events.hpp"
#define ZTS_STATE_NODE_RUNNING 0x01
#define ZTS_STATE_STACK_RUNNING 0x02
#define ZTS_STATE_NET_SERVICE_RUNNING 0x04
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
#define ZTS_STATE_FREE_CALLED 0x10
#define ZTS_STATE_NODE_RUNNING 0x01
#define ZTS_STATE_STACK_RUNNING 0x02
#define ZTS_STATE_NET_SERVICE_RUNNING 0x04
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
#define ZTS_STATE_FREE_CALLED 0x10
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#include <jni.h>
#endif
@@ -45,7 +44,7 @@ extern uint8_t _serviceStateFlags;
extern "C" {
#endif
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
void ss2zta(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr);
void zta2ss(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr);
void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set);
@@ -59,7 +58,7 @@ int zts_socket(const int socket_family, const int socket_type, const int protoco
}
return lwip_socket(socket_family, socket_type, protocol);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_socket(
JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol)
{
@@ -81,7 +80,7 @@ int zts_connect(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen)
}
return lwip_connect(fd, (sockaddr*)addr, addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_connect(
JNIEnv *env, jobject thisObj, jint fd, jobject addr)
{
@@ -106,7 +105,8 @@ int zts_bind(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen)
}
return lwip_bind(fd, (sockaddr*)addr, addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_bind(
JNIEnv *env, jobject thisObj, jint fd, jobject addr)
{
@@ -125,7 +125,7 @@ int zts_listen(int fd, int backlog)
}
return lwip_listen(fd, backlog);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_listen(
JNIEnv *env, jobject thisObj, jint fd, int backlog)
{
@@ -141,7 +141,7 @@ int zts_accept(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen)
}
return lwip_accept(fd, (sockaddr*)addr, (socklen_t*)addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept(
JNIEnv *env, jobject thisObj, jint fd, jobject addr, jint port)
{
@@ -162,7 +162,7 @@ int zts_accept4(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen, int f
return ZTS_ERR_SERVICE; // TODO
}
#endif
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#if defined(__linux__)
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept4(
JNIEnv *env, jobject thisObj, jint fd, jobject addr, jint port, jint flags)
@@ -183,7 +183,7 @@ int zts_setsockopt(int fd, int level, int optname, const void *optval,zts_sockle
}
return lwip_setsockopt(fd, level, optname, optval, optlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt(
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jobject optval)
{
@@ -236,7 +236,7 @@ int zts_getsockopt(int fd, int level, int optname, void *optval, zts_socklen_t *
}
return lwip_getsockopt(fd, level, optname, optval, (socklen_t*)optlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt(
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jobject optval)
{
@@ -259,7 +259,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt(
else {
retval = zts_getsockopt(fd, level, optname, &optval_int, &optlen);
}
if (optname == SO_BROADCAST
|| optname == SO_KEEPALIVE
|| optname == SO_REUSEADDR
@@ -300,14 +300,14 @@ int zts_getsockname(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen)
}
return lwip_getsockname(fd, (sockaddr*)addr, (socklen_t*)addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_getsockname(JNIEnv *env, jobject thisObj,
jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage);
int retval = zts_getsockname(fd, (struct zts_sockaddr *)&ss, &addrlen);
ss2zta(env, &ss, addr);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -325,13 +325,13 @@ int zts_getpeername(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen)
}
return lwip_getpeername(fd, (sockaddr*)addr, (socklen_t*)addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getpeername(JNIEnv *env, jobject thisObj,
jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
int retval = zts_getpeername(fd, (struct zts_sockaddr *)&ss, (zts_socklen_t*)sizeof(struct zts_sockaddr_storage));
ss2zta(env, &ss, addr);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -343,7 +343,7 @@ int zts_close(int fd)
}
return lwip_close(fd);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_close(
JNIEnv *env, jobject thisObj, jint fd)
{
@@ -359,7 +359,7 @@ int zts_select(int nfds, zts_fd_set *readfds, zts_fd_set *writefds, zts_fd_set *
}
return lwip_select(nfds, (fd_set*)readfds, (fd_set*)writefds, (fd_set*)exceptfds, (timeval*)timeout);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_select(JNIEnv *env, jobject thisObj,
jint nfds, jobject readfds, jobject writefds, jobject exceptfds, jint timeout_sec, jint timeout_usec)
{
@@ -391,7 +391,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_select(JNIEnv *env, jobj
}
if (exceptfds) {
fdset2ztfdset(env, nfds, &_exceptfds, exceptfds);
}
}
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -403,7 +403,7 @@ int zts_fcntl(int fd, int cmd, int flags)
}
return lwip_fcntl(fd, cmd, flags);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_fcntl(
JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags)
{
@@ -431,14 +431,14 @@ int zts_ioctl(int fd, unsigned long request, void *argp)
}
return lwip_ioctl(fd, request, argp);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl(
JNIEnv *env, jobject thisObj, jint fd, jlong request, jobject argp)
{
int retval = ZTS_ERR_OK;
if (request == FIONREAD) {
int bytesRemaining = 0;
retval = zts_ioctl(fd, request, &bytesRemaining);
retval = zts_ioctl(fd, request, &bytesRemaining);
// set value in general object
jclass c = env->GetObjectClass(argp);
if (!c) {
@@ -450,7 +450,7 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl(
if (request == FIONBIO) {
// TODO: double check
int meaninglessVariable = 0;
retval = zts_ioctl(fd, request, &meaninglessVariable);
retval = zts_ioctl(fd, request, &meaninglessVariable);
}
return retval > -1 ? retval : -(zts_errno);
}
@@ -466,18 +466,18 @@ ssize_t zts_send(int fd, const void *buf, size_t len, int flags)
}
return lwip_send(fd, buf, len, flags);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_send(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, int flags)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_send(fd, data, env->GetArrayLength(buf), flags);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
#endif
ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags,
ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags,
const struct zts_sockaddr *addr,zts_socklen_t addrlen)
{
if (!addr || !buf) {
@@ -491,7 +491,7 @@ ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags,
}
return lwip_sendto(fd, buf, len, flags, (sockaddr*)addr, addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr)
{
@@ -500,7 +500,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto(
zta2ss(env, &ss, addr);
zts_socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6);
int retval = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, addrlen);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -512,7 +512,7 @@ ssize_t zts_sendmsg(int fd, const struct msghdr *msg, int flags)
}
return lwip_sendmsg(fd, msg, flags);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
ssize_t zts_recv(int fd, void *buf, size_t len, int flags)
@@ -525,7 +525,7 @@ ssize_t zts_recv(int fd, void *buf, size_t len, int flags)
}
return lwip_recv(fd, buf, len, flags);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf, jint flags)
{
@@ -536,7 +536,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobjec
}
#endif
ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags,
ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags,
struct zts_sockaddr *addr, zts_socklen_t *addrlen)
{
if (!buf) {
@@ -547,7 +547,7 @@ ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags,
}
return lwip_recvfrom(fd, buf, len, flags, (sockaddr*)addr, (socklen_t*)addrlen);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recvfrom(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr)
{
@@ -556,7 +556,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recvfrom(
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, &addrlen);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
ss2zta(env, &ss, addr);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -572,7 +572,7 @@ ssize_t zts_recvmsg(int fd, struct msghdr *msg, int flags)
}
return lwip_recvmsg(fd, msg, flags);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
ssize_t zts_read(int fd, void *buf, size_t len)
@@ -596,13 +596,13 @@ ssize_t zts_read_offset(int fd, void *buf, size_t offset, size_t len)
char *cbuf = (char*)buf;
return lwip_read(fd, &(cbuf[offset]), len);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read(fd, data, env->GetArrayLength(buf));
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1offset(JNIEnv *env, jobject thisObj,
@@ -610,7 +610,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1offset(JNIEnv *env
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read_offset(fd, data, offset, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1length(JNIEnv *env, jobject thisObj,
@@ -618,7 +618,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1length(JNIEnv *env
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read(fd, data, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
#endif
@@ -642,13 +642,13 @@ ssize_t zts_write(int fd, const void *buf, size_t len)
}
return lwip_write(fd, buf, len);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write__IB(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_write(fd, data, env->GetArrayLength(buf));
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1offset(JNIEnv *env, jobject thisObj,
@@ -656,7 +656,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1offset(JNIEnv *en
{
void *data = env->GetPrimitiveArrayCritical(&(buf[offset]), NULL); // PENDING: check?
int retval = zts_write(fd, data, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1byte(JNIEnv *env, jobject thisObj,
@@ -683,7 +683,7 @@ int zts_shutdown(int fd, int how)
}
return lwip_shutdown(fd, how);
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_shutdown(
JNIEnv *env, jobject thisObj, int fd, int how)
{
@@ -698,7 +698,7 @@ int zts_add_dns_nameserver(struct zts_sockaddr *addr)
}
return ZTS_ERR_SERVICE; // TODO
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
int zts_del_dns_nameserver(struct zts_sockaddr *addr)
@@ -708,7 +708,7 @@ int zts_del_dns_nameserver(struct zts_sockaddr *addr)
}
return ZTS_ERR_SERVICE; // TODO
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
#endif
uint16_t zts_htons(uint16_t n)
@@ -750,6 +750,8 @@ uint32_t zts_inet_addr(const char *cp)
// Statistics //
//////////////////////////////////////////////////////////////////////////////
#ifdef ZTS_ENABLE_STATS
extern struct stats_ lwip_stats;
int zts_get_all_stats(struct zts_stats *statsDest)
@@ -785,7 +787,7 @@ int zts_get_all_stats(struct zts_stats *statsDest)
return ZTS_ERR_NO_RESULT;
#endif
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
// No implementation for JNI
#endif
@@ -836,7 +838,7 @@ int zts_get_protocol_stats(int protocolType, void *protoStatsDest)
return ZTS_ERR_NO_RESULT;
#endif
}
#ifdef SDK_JNI
#ifdef ZTS_ENABLE_JAVA
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1protocol_1stats(
JNIEnv *env, jobject thisObj, jint protocolType, jobject protoStatsObj)
{
@@ -876,7 +878,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1protocol_1stats(
}
#endif
#ifdef SDK_JNI
#endif // ZTS_ENABLE_STATS
#ifdef ZTS_ENABLE_JAVA
void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set)
{
jclass c = env->GetObjectClass(src_ztfd_set);

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c)2013-2021 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.
*/
/****/
/**
* @file
*
* ZeroTier Socket API (Python)
*/
#include "lwip/sockets.h"
#include "ZeroTierSockets.h"
#ifdef ZTS_ENABLE_PYTHON
int zts_py_setblocking(int fd, int flag)
{
int flags = ZTS_ERR_OK;
if ((flags = zts_fcntl(fd, F_GETFL, 0)) < 0) {
return ZTS_ERR_SOCKET;
}
return zts_fcntl(fd, F_SETFL, flags | ZTS_O_NONBLOCK);
}
int zts_py_getblocking(int fd)
{
int flags = ZTS_ERR_OK;
if ((flags = zts_fcntl(fd, F_GETFL, 0)) < 0) {
return ZTS_ERR_SOCKET;
}
return flags & ZTS_O_NONBLOCK;
}
static int zts_py_tuple_to_sockaddr(int family,
PyObject *addr_obj, struct zts_sockaddr *dst_addr, int *addrlen)
{
if (family == AF_INET) {
struct zts_sockaddr_in* addr;
char *host_str;
int result, port;
if (!PyTuple_Check(addr_obj)) {
return ZTS_ERR_ARG;
}
if (!PyArg_ParseTuple(addr_obj,
"eti:zts_py_tuple_to_sockaddr", "idna", &host_str, &port)) {
return ZTS_ERR_ARG;
}
addr = (struct zts_sockaddr_in*)dst_addr;
addr->sin_addr.s_addr = zts_inet_addr(host_str);
PyMem_Free(host_str);
if (port < 0 || port > 0xFFFF) {
return ZTS_ERR_ARG;
}
if (result < 0) {
return ZTS_ERR_ARG;
}
addr->sin_family = AF_INET;
addr->sin_port = htons((short)port);
*addrlen = sizeof *addr;
return ZTS_ERR_OK;
}
if (family == AF_INET6) {
// TODO
}
return ZTS_ERR_ARG;
}
PyObject * zts_py_accept(int fd)
{
struct zts_sockaddr_in addrbuf;
socklen_t addrlen = sizeof(addrbuf);
memset(&addrbuf, 0, addrlen);
int err = zts_accept(fd, (struct zts_sockaddr*)&addrbuf, &addrlen);
char ipstr[ZTS_INET_ADDRSTRLEN];
memset(ipstr, 0, sizeof(ipstr));
zts_inet_ntop(ZTS_AF_INET, &(addrbuf.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
PyObject *t;
t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(err)); // New file descriptor
PyTuple_SetItem(t, 1, PyUnicode_FromString(ipstr));
PyTuple_SetItem(t, 2, PyLong_FromLong(zts_ntohs(addrbuf.sin_port)));
Py_INCREF(t);
return t;
}
int zts_py_listen(int fd, int backlog)
{
return zts_listen(fd, backlog);
}
int zts_py_bind(int fd, int family, int type, PyObject *addr_obj)
{
struct zts_sockaddr_storage addrbuf;
int addrlen;
int err;
if (zts_py_tuple_to_sockaddr(family, addr_obj,
(struct zts_sockaddr *)&addrbuf, &addrlen) != ZTS_ERR_OK)
{
return ZTS_ERR_ARG;
}
Py_BEGIN_ALLOW_THREADS
err = zts_bind(fd, (struct zts_sockaddr *)&addrbuf, addrlen);
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return err;
}
int zts_py_connect(int fd, int family, int type, PyObject *addr_obj)
{
struct zts_sockaddr_storage addrbuf;
int addrlen;
int err;
if (zts_py_tuple_to_sockaddr(family, addr_obj,
(struct zts_sockaddr *)&addrbuf, &addrlen) != ZTS_ERR_OK)
{
return ZTS_ERR_ARG;
}
Py_BEGIN_ALLOW_THREADS
err = zts_connect(fd, (struct zts_sockaddr *)&addrbuf, addrlen);
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return err;
}
PyObject * zts_py_recv(int fd, int len, int flags)
{
PyObject *t;
char buf[4096];
int err = zts_recv(fd, buf, len, flags);
if (err < 0) {
return NULL;
}
t = PyTuple_New(2);
PyTuple_SetItem(t, 0, PyLong_FromLong(err));
PyTuple_SetItem(t, 1, PyUnicode_FromString(buf));
Py_INCREF(t);
return t;
}
int zts_py_send(int fd, PyObject *buf, int len, int flags)
{
int err = ZTS_ERR_OK;
PyObject *encodedStr = PyUnicode_AsEncodedString(buf, "UTF-8", "strict");
if (encodedStr) {
char *bytes = PyBytes_AsString(encodedStr);
err = zts_send(fd, bytes, len, flags);
Py_DECREF(encodedStr);
}
return err;
}
int zts_py_close(int fd)
{
return zts_close(fd);
}
#endif // ZTS_ENABLE_PYTHON

View File

@@ -0,0 +1,4 @@
# Python Language Bindings
- Install (via [PyPI package](https://pypi.org/project/libzt/)): `pip install libzt`
- Example usage: [examples/python](./../../../examples/python/)

View File

@@ -0,0 +1,408 @@
"""ZeroTier low-level socket interface"""
import libzt
class EventCallbackClass(libzt.PythonDirectorCallbackClass):
"""ZeroTier event callback class"""
pass
def handle_error(err):
"""Convert libzt error code to exception"""
if err == libzt.ZTS_ERR_SOCKET:
raise Exception("ZTS_ERR_SOCKET (" + str(err) + ")")
if err == libzt.ZTS_ERR_SERVICE:
raise Exception("ZTS_ERR_SERVICE (" + str(err) + ")")
if err == libzt.ZTS_ERR_ARG:
raise Exception("ZTS_ERR_ARG (" + str(err) + ")")
# ZTS_ERR_NO_RESULT isn't strictly an error
# if (err == libzt.ZTS_ERR_NO_RESULT):
# raise Exception('ZTS_ERR_NO_RESULT (' + err + ')')
if err == libzt.ZTS_ERR_GENERAL:
raise Exception("ZTS_ERR_GENERAL (" + str(err) + ")")
# This implementation of errno is NOT thread safe
# That is, this value is shared among all lower-level socket calls
# and may change for any reason at any time if you have multiple
# threads making socket calls.
def errno():
"""Return errno value of low-level socket layer"""
return libzt.cvar.zts_errno
def start(path, callback, port):
"""Start the ZeroTier service"""
libzt.zts_start(path, callback, port)
def stop():
"""Stop the ZeroTier service"""
libzt.zts_stop()
def restart():
"""[debug] Restarts the ZeroTier service and network stack"""
libzt.zts_restart()
def free():
"""Permenantly shuts down the network stack"""
libzt.zts_free()
def join(network_id):
"""Join a ZeroTier network"""
libzt.zts_join(network_id)
def leave(network_id):
"""Leave a ZeroTier network"""
libzt.zts_leave(network_id)
def zts_orbit(moon_world_id, moon_seed):
"""Orbit a moon"""
return libzt.zts_orbit(moon_world_id, moon_seed)
def zts_deorbit(moon_world_id):
"""De-orbit a moon"""
return libzt.zts_deorbit(moon_world_id)
class socket:
"""Pythonic class that wraps low-level sockets"""
_fd = -1 # native layer file descriptor
_family = -1
_type = -1
_proto = -1
_connected = False
_closed = True
_bound = False
def __init__(self, sock_family=-1, sock_type=-1, sock_proto=-1, sock_fd=None):
self._fd = sock_fd
self._family = sock_family
self._type = sock_type
self._family = sock_family
# Only create native socket if no fd was provided. We may have
# accepted a connection
if sock_fd is None:
self._fd = libzt.zts_socket(sock_family, sock_type, sock_proto)
def has_dualstack_ipv6(self):
"""Return whether libzt supports dual stack sockets: yes"""
return True
@property
def family(self):
"""Return family of socket"""
return self._family
@property
def type(self):
"""Return type of socket"""
return self._type
@property
def proto(self):
"""Return protocol of socket"""
return self._proto
def socketpair(self, sock_family, sock_type, sock_proto):
"""Intentionally not supported"""
raise NotImplementedError(
"socketpair(): libzt does not support AF_UNIX sockets"
)
def create_connection(self, remote_address):
"""Convenience function to create a connection to a remote host"""
# TODO: implement timeout
conn = socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
conn.connect(remote_address)
return conn
def create_server(self, local_address, sock_family=libzt.ZTS_AF_INET, backlog=None):
"""Convenience function to create a listening socket"""
# TODO: implement reuse_port
conn = socket(sock_family, libzt.ZTS_SOCK_STREAM, 0)
conn.bind(local_address)
conn.listen(backlog)
return conn
def fromfd(self, fd, sock_family, sock_type, sock_proto=0):
"""libzt does not support this (yet)"""
raise NotImplementedError(
"fromfd(): Not supported. OS File descriptors aren't used in libzt."
)
def fromshare(self, data):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getaddrinfo(self, host, port, sock_family=0, sock_type=0, sock_proto=0, flags=0):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getfqdn(self, name):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname(self, hostname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname_ex(self, hostname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostname(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyaddr(self, ip_address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getnameinfo(self, sockaddr, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getprotobyname(self, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyname(self, servicename, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyport(self, port, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ntohl(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ntohs(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def htonl(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def htons(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_aton(ip_string):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntoa(packed_ip):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_pton(address_family, ip_string):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntop(address_family, packed_ip):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_LEN(length):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_SPACE(length):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getdefaulttimeout(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def setdefaulttimeout(self, timeout):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sethostname(self, name):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def if_nameindex(self):
"""libzt does not support this"""
raise NotImplementedError("if_nameindex(): libzt does not name interfaces.")
def if_nametoindex(self, if_name):
"""libzt does not support this"""
raise NotImplementedError("if_nametoindex(): libzt does not name interfaces.")
def if_indextoname(self, if_index):
"""libzt does not support this"""
raise NotImplementedError("if_indextoname(): libzt does not name interfaces.")
def accept(self):
"""Accept connection on the socket"""
new_conn_fd, addr, port = libzt.zts_py_accept(self._fd)
if new_conn_fd < 0:
handle_error(new_conn_fd)
return None
return socket(self._family, self._type, self._proto, new_conn_fd), addr
def bind(self, local_address):
"""Bind the socket to a local interface address"""
err = libzt.zts_py_bind(self._fd, self._family, self._type, local_address)
if err < 0:
handle_error(err)
def close(self):
"""Close the socket"""
err = libzt.zts_py_close(self._fd)
if err < 0:
handle_error(err)
def connect(self, remote_address):
"""Connect the socket to a remote address"""
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
if err < 0:
handle_error(err)
def connect_ex(self, remote_address):
"""Connect to remote host but return low-level result code, and errno on failure
This uses a non-thread-safe implementation of errno
"""
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
if err < 0:
return errno()
return err
def detach(self):
"""libzt does not support this"""
raise NotImplementedError(
"detach(): Not supported. OS File descriptors aren't used in libzt.")
def dup(self):
"""libzt does not support this"""
raise NotImplementedError("libzt does not support this (yet?)")
def fileno(self):
"""libzt does not support this"""
raise NotImplementedError("libzt does not support this (yet?)")
def get_inheritable(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getpeername(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getsockname(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getsockopt(self, level, optname, buflen):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getblocking(self):
"""Get whether this socket is in blocking or non-blocking mode"""
return libzt.zts_py_getblocking(self._fd)
def gettimeout(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ioctl(self, control, option):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def listen(self, backlog):
"""Put the socket in a listening state (with an optional backlog argument)"""
err = libzt.zts_py_listen(self._fd, backlog)
if err < 0:
handle_error(err)
def makefile(mode="r", buffering=None, *, encoding=None, errors=None, newline=None):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv(self, n_bytes, flags=0):
"""Read data from the socket"""
err, data = libzt.zts_py_recv(self._fd, n_bytes, flags)
if err < 0:
handle_error(err)
return None
return data
def recvfrom(self, bufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg(self, bufsize, ancbufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg_into(self, buffers, ancbufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvfrom_into(self, buffer, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv_into(self, buffer, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def send(self, data, flags=0):
"""Write data to the socket"""
err = libzt.zts_py_send(self._fd, data, len(data), flags)
if err < 0:
handle_error(err)
return err
def sendall(self, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendto(self, n_bytes, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg(self, buffers, ancdata, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg_afalg(self, msg, *, op, iv, assoclen, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("sendmsg_afalg(): libzt does not support AF_ALG")
def send_fds(self, sock, buffers, fds, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv_fds(self, sock, bufsize, maxfds, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendfile(self, file, offset=0, count=None):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def set_inheritable(self, inheritable):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def setblocking(self, flag):
"""Set whether this socket is in blocking or non-blocking mode"""
libzt.zts_py_setblocking(self._fd, flag)
def settimeout(self, value):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
# TODO: value: buffer
# TODO: value: int
# TODO: value: None -> optlen required
def setsockopt(self, level, optname, value):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def shutdown(self, how):
"""Shut down one or more aspects (rx/tx) of the socket"""
libzt.zts_shutdown(self._fd, how)

39
src/bindings/python/zt.i Normal file
View File

@@ -0,0 +1,39 @@
/* libzt.i */
%begin
%{
#define SWIG_PYTHON_CAST_MODE
%}
%include <stdint.i>
#define ZTS_ENABLE_PYTHON 1
%module(directors="1") libzt
%module libzt
%{
#include "ZeroTierSockets.h"
%}
%feature("director") PythonDirectorCallbackClass;
%ignore zts_in6_addr;
%ignore zts_sockaddr;
%ignore zts_in_addr;
%ignore zts_sockaddr_in;
%ignore zts_sockaddr_storage;
%ignore zts_sockaddr_in6;
%ignore zts_linger;
%ignore zts_accept4;
%ignore zts_ip_mreq;
%ignore zts_in_pktinfo;
%ignore zts_ipv6_mreq;
%ignore zts_fd_set;
%ignore zts_pollfd;
%ignore zts_nfds_t;
%ignore zts_msghdr;
%ignore zts_inet_addr;
%include "ZeroTierSockets.h"

View File

@@ -1,248 +0,0 @@
/*
* 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: 2024-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 com.zerotier.libzt;
import java.net.*;
public class ZeroTier
{
//////////////////////////////////////////////////////////////////////////////
// Control API error codes //
//////////////////////////////////////////////////////////////////////////////
// Everything is ok
public static int ZTS_ERR_OK = 0;
// Error
public static int ZTS_ERR = -1;
// A argument provided by the user application is invalid (e.g. out of range, NULL, etc)
public static int ZTS_ERR_INVALID_ARG = -2;
// The service isn't initialized or is for some reason currently unavailable. Try again.
public static int ZTS_ERR_SERVICE = -3;
// For some reason this API operation is not permitted or doesn't make sense at this time.
public static int ZTS_ERR_INVALID_OP = -4;
// The call succeeded, but no object or relevant result was available
public static int ZTS_ERR_NO_RESULT = -5;
// General internal failure
public static int ZTS_ERR_GENERAL = -6;
//////////////////////////////////////////////////////////////////////////////
// Static initialization //
//////////////////////////////////////////////////////////////////////////////
static
{
// loads libzt.so or libzt.dylib
System.loadLibrary("zt");
// Give the native code a reference to this VM (for callbacks)
if (init() != ZTS_ERR_OK) {
throw new ExceptionInInitializerError("JNI init() failed (see GetJavaVM())");
}
}
//////////////////////////////////////////////////////////////////////////////
// Control API event codes //
//////////////////////////////////////////////////////////////////////////////
public static int EVENT_NONE = -1;
// Node-specific events
public static int EVENT_NODE_UP = 0;
public static int EVENT_NODE_OFFLINE = 1;
public static int EVENT_NODE_ONLINE = 2;
public static int EVENT_NODE_DOWN = 3;
public static int EVENT_NODE_IDENTITY_COLLISION = 4;
// libzt node events
public static int EVENT_NODE_UNRECOVERABLE_ERROR = 16;
public static int EVENT_NODE_NORMAL_TERMINATION = 17;
// Network-specific events
public static int EVENT_NETWORK_NOT_FOUND = 32;
public static int EVENT_NETWORK_CLIENT_TOO_OLD = 33;
public static int EVENT_NETWORK_REQUESTING_CONFIG = 34;
public static int EVENT_NETWORK_OK = 35;
public static int EVENT_NETWORK_ACCESS_DENIED = 36;
public static int EVENT_NETWORK_READY_IP4 = 37;
public static int EVENT_NETWORK_READY_IP6 = 38;
public static int EVENT_NETWORK_READY_IP4_IP6 = 39;
public static int EVENT_NETWORK_DOWN = 40;
// lwIP netif events
public static int EVENT_NETIF_UP_IP4 = 64;
public static int EVENT_NETIF_UP_IP6 = 65;
public static int EVENT_NETIF_DOWN_IP4 = 66;
public static int EVENT_NETIF_DOWN_IP6 = 67;
public static int EVENT_NETIF_REMOVED = 68;
public static int EVENT_NETIF_LINK_UP = 69;
public static int EVENT_NETIF_LINK_DOWN = 70;
public static int EVENT_NETIF_NEW_ADDRESS = 71;
// Peer events
public static int EVENT_PEER_P2P = 96;
public static int EVENT_PEER_RELAY = 97;
public static int EVENT_PEER_UNREACHABLE = 98;
//////////////////////////////////////////////////////////////////////////////
// ZeroTier Constants //
//////////////////////////////////////////////////////////////////////////////
public static int ZT_MAX_PEER_NETWORK_PATHS = 16;
//////////////////////////////////////////////////////////////////////////////
// Socket API Constants //
//////////////////////////////////////////////////////////////////////////////
// Socket protocol types
public static int SOCK_STREAM = 0x00000001;
public static int SOCK_DGRAM = 0x00000002;
public static int SOCK_RAW = 0x00000003;
// Socket family types
public static int AF_INET = 0x00000002;
public static int AF_INET6 = 0x0000000a;
public static int PF_INET = AF_INET;
public static int PF_INET6 = AF_INET6;
// Used as level numbers for setsockopt() and getsockopt()
public static int IPPROTO_IP = 0x00000000;
public static int IPPROTO_ICMP = 0x00000001;
public static int IPPROTO_TCP = 0x00000006;
public static int IPPROTO_UDP = 0x00000011;
public static int IPPROTO_IPV6 = 0x00000029;
public static int IPPROTO_ICMPV6 = 0x0000003a;
public static int IPPROTO_UDPLITE = 0x00000088;
public static int IPPROTO_RAW = 0x000000ff;
// send() and recv() flags
public static int MSG_PEEK = 0x00000001;
public static int MSG_WAITALL = 0x00000002;
public static int MSG_OOB = 0x00000004;
public static int MSG_DONTWAIT = 0x00000008;
public static int MSG_MORE = 0x00000010;
// fnctl() commands
public static int F_GETFL = 0x00000003;
public static int F_SETFL = 0x00000004;
// fnctl() flags
public static int O_NONBLOCK = 0x00000001;
public static int O_NDELAY = 0x00000001;
// Shutdown commands
public static int SHUT_RD = 0x00000000;
public static int SHUT_WR = 0x00000001;
public static int SHUT_RDWR = 0x00000002;
// ioctl() commands
public static int FIONREAD = 0x4008667F;
public static int FIONBIO = 0x8008667E;
// Socket level option number
public static int SOL_SOCKET = 0x00000FFF;
// Socket options
public static int SO_REUSEADDR = 0x00000004;
public static int SO_KEEPALIVE = 0x00000008;
public static int SO_BROADCAST = 0x00000020;
// Socket options
public static int SO_DEBUG = 0x00000001; // NOT YET SUPPORTED
public static int SO_ACCEPTCONN = 0x00000002;
public static int SO_DONTROUTE = 0x00000010; // NOT YET SUPPORTED
public static int SO_USELOOPBACK = 0x00000040; // NOT YET SUPPORTED
public static int SO_LINGER = 0x00000080;
public static int SO_DONTLINGER = ((int)(~SO_LINGER));
public static int SO_OOBINLINE = 0x00000100; // NOT YET SUPPORTED
public static int SO_REUSEPORT = 0x00000200; // NOT YET SUPPORTED
public static int SO_SNDBUF = 0x00001001; // NOT YET SUPPORTED
public static int SO_RCVBUF = 0x00001002;
public static int SO_SNDLOWAT = 0x00001003; // NOT YET SUPPORTED
public static int SO_RCVLOWAT = 0x00001004; // NOT YET SUPPORTED
public static int SO_SNDTIMEO = 0x00001005;
public static int SO_RCVTIMEO = 0x00001006;
public static int SO_ERROR = 0x00001007;
public static int SO_TYPE = 0x00001008;
public static int SO_CONTIMEO = 0x00001009; // NOT YET SUPPORTED
public static int SO_NO_CHECK = 0x0000100a;
// IPPROTO_IP options
public static int IP_TOS = 0x00000001;
public static int IP_TTL = 0x00000002;
// IPPROTO_TCP options
public static int TCP_NODELAY = 0x00000001;
public static int TCP_KEEPALIVE = 0x00000002;
public static int TCP_KEEPIDLE = 0x00000003;
public static int TCP_KEEPINTVL = 0x00000004;
public static int TCP_KEEPCNT = 0x00000005;
//////////////////////////////////////////////////////////////////////////////
// Statistics //
//////////////////////////////////////////////////////////////////////////////
public static int STATS_PROTOCOL_LINK = 0;
public static int STATS_PROTOCOL_ETHARP = 1;
public static int STATS_PROTOCOL_IP = 2;
public static int STATS_PROTOCOL_UDP = 3;
public static int STATS_PROTOCOL_TCP = 4;
public static int STATS_PROTOCOL_ICMP = 5;
public static int STATS_PROTOCOL_IP_FRAG = 6;
public static int STATS_PROTOCOL_IP6 = 7;
public static int STATS_PROTOCOL_ICMP6 = 8;
public static int STATS_PROTOCOL_IP6_FRAG = 9;
public static native int get_protocol_stats(int protocolNum, ZeroTierProtoStats stats);
//////////////////////////////////////////////////////////////////////////////
// ZeroTier Service Controls //
//////////////////////////////////////////////////////////////////////////////
public static native int start(String path, ZeroTierEventListener callbackClass, int port);
public static native int stop();
public static native int restart();
public static native int join(long nwid);
public static native int leave(long nwid);
public static native long get_node_id();
public static native int get_num_assigned_addresses(long nwid);
public static native void get_6plane_addr(long nwid, long nodeId, ZeroTierSocketAddress addr);
public static native void get_rfc4193_addr(long nwid, long nodeId, ZeroTierSocketAddress addr);
public static native int get_node_status();
public static native int get_network_status(long networkId);
public static native int get_peer_status(long peerId);
public static native int get_peer(long peerId, ZeroTierPeerDetails details);
//////////////////////////////////////////////////////////////////////////////
// Socket API //
//////////////////////////////////////////////////////////////////////////////
public static native int socket(int family, int type, int protocol);
public static native int connect(int fd, ZeroTierSocketAddress addr);
public static native int bind(int fd, ZeroTierSocketAddress addr);
public static native int listen(int fd, int backlog);
public static native int accept(int fd, ZeroTierSocketAddress addr);
public static native int accept4(int fd, String addr, int port);
public static native int setsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval);
public static native int getsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval);
public static native int read(int fd, byte[] buf);
public static native int read_offset(int fd, byte[] buf, int offset, int len);
public static native int read_length(int fd, byte[] buf, int len);
public static native int recv(int fd, byte[] buf, int flags);
public static native int recvfrom(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr);
public static native int write(int fd, byte[] buf);
public static native int write_byte(int fd, byte b);
public static native int write_offset(int fd, byte[] buf, int offset, int len);
public static native int sendto(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr);
public static native int send(int fd, byte[] buf, int flags);
public static native int shutdown(int fd, int how);
public static native int close(int fd);
public static native boolean getsockname(int fd, ZeroTierSocketAddress addr);
public static native int getpeername(int fd, ZeroTierSocketAddress addr);
public static native int fcntl(int sock, int cmd, int flag);
public static native int ioctl(int fd, long request, ZeroTierIoctlArg arg);
public static native int select(int nfds, ZeroTierFileDescriptorSet readfds, ZeroTierFileDescriptorSet writefds, ZeroTierFileDescriptorSet exceptfds, int timeout_sec, int timeout_usec);
//////////////////////////////////////////////////////////////////////////////
// Internal - Do not call //
//////////////////////////////////////////////////////////////////////////////
public static native int init(); // Only to be called by static initializer of this class
}

View File

@@ -1,9 +0,0 @@
package com.zerotier.libzt;
public interface ZeroTierEventListener {
/*
* Called when an even occurs in the native section of the ZeroTier library service
*/
public void onZeroTierEvent(long nwid, int eventCode);
}

View File

@@ -1,28 +0,0 @@
package com.zerotier.libzt;
public class ZeroTierFileDescriptorSet
{
byte[] fds_bits = new byte[1024];
public void CLR(int fd)
{
fds_bits[fd] = 0x00;
}
public boolean ISSET(int fd)
{
return fds_bits[fd] == 0x01;
}
public void SET(int fd)
{
fds_bits[fd] = 0x01;
}
public void ZERO()
{
for (int i=0; i<1024; i++) {
fds_bits[i] = 0x00;
}
}
}

View File

@@ -1,209 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import java.io.*;
import java.util.Objects;
public class ZeroTierInputStream extends InputStream
{
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
private static final int DEFAULT_BUFFER_SIZE = 8192;
/*
* File descriptor used by lower native layer
*/
int zfd;
/*
*
*/
public int available()
throws IOException
{
return 0; // NOT YET SUPPORTED
}
/*
*
*/
public void close()
throws IOException
{
/* Note: this operation currently only stops RX on a socket that is shared
between both I/OStreams. This means that closing this stream will only shutdown
that aspect of the socket but not actually close it and free resources. Resources
will be properly freed when the socket implementation's close() is called or if
both I/OStreams are closed separately */
ZeroTier.shutdown(zfd, ZeroTier.SHUT_RD);
zfd = -1;
}
/*
*
*/
public void mark(int readlimit)
{
System.err.println("mark: ZeroTierInputStream does not currently support this feature");
}
/*
*
*/
public void reset()
throws IOException
{
System.err.println("reset: ZeroTierInputStream does not currently support this feature");
}
/*
*
*/
public boolean markSupported()
{
return false; // mark() is not supported
}
/*
*
*/
public long transferTo(OutputStream out)
throws IOException
{
Objects.requireNonNull(out, "out must not be null");
int bytesTransferred = 0, bytesRead;
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
while (((bytesRead = ZeroTier.read(zfd, buf)) >= 0)) {
out.write(buf, 0, bytesRead);
bytesTransferred += bytesRead;
}
return bytesTransferred;
}
/*
*
*/
public int read()
throws IOException
{
byte[] buf = new byte[1];
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTier.read(zfd, buf);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(), errno="+retval);
}
return buf[0];
}
/*
*
*/
public int read(byte[] b)
throws IOException
{
Objects.requireNonNull(b, "input byte array must not be null");
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTier.read(zfd, b);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(b), errno="+retval);
}
return retval;
}
/*
*
*/
public int read(byte[] b, int off, int len)
throws IOException
{
Objects.requireNonNull(b, "input byte array must not be null");
if ((off < 0) | (len < 0) | (len > b.length - off)) {
throw new IndexOutOfBoundsException("invalid argument");
}
if (len == 0) {
return 0;
}
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTier.read_offset(zfd, b, off, len);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(b,off,len), errno="+retval);
}
//System.out.println("readNBytes(byte[] b, int off="+off+", int len="+len+")="+retval);
return retval;
}
/*
*
*/
public byte[] readAllBytes()
throws IOException
{
//System.out.println("readAllBytes()");
ZeroTierIoctlArg ztarg = new ZeroTierIoctlArg();
int err = ZeroTier.ioctl(zfd, ZeroTier.FIONREAD, ztarg);
byte[] buf = new byte[ztarg.integer];
int retval = ZeroTier.read(zfd, buf);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
// No action needed
}
if (retval < 0) {
throw new IOException("readAllBytes(b,off,len), errno="+retval);
}
return buf;
}
/*
*
*/
public int readNBytes(byte[] b, int off, int len)
throws IOException
{
Objects.requireNonNull(b, "input byte array must not be null");
if ((off < 0) | (len < 0) | (len > b.length - off)) {
throw new IndexOutOfBoundsException("invalid argument");
}
if (len == 0) {
return 0;
}
int retval = ZeroTier.read_offset(zfd, b, off, len);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
// No action needed
}
if (retval < 0) {
throw new IOException("readNBytes(b,off,len), errno="+retval);
}
//System.out.println("readNBytes(byte[] b, int off="+off+", int len="+len+")="+retval);
return retval;
}
/*
*
*/
public long skip(long n)
throws IOException
{
//System.out.println("skip()");
if (n <= 0) {
return 0;
}
long bytesRemaining = n, bytesRead;
int bufSize = (int)Math.min(MAX_SKIP_BUFFER_SIZE, bytesRemaining);
byte[] buf = new byte[bufSize];
while (bytesRemaining > 0) {
if ((bytesRead = ZeroTier.read_length(zfd, buf, (int)Math.min(bufSize, bytesRemaining))) < 0) {
break;
}
bytesRemaining -= bytesRead;
}
return n - bytesRemaining; // skipped
}
}

View File

@@ -1,6 +0,0 @@
package com.zerotier.libzt;
public class ZeroTierIoctlArg
{
int integer; // General integer to be used or updated by the zts_ioctl() call
}

View File

@@ -1,81 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import java.io.*;
import java.util.Arrays;
import java.util.Objects;
class ZeroTierOutputStream extends OutputStream
{
/*
* File descriptor used by lower native layer
*/
int zfd;
/*
*
*/
public void flush()
throws IOException
{
// System.err.println("flush: ZeroTierOutputStream does not currently support this feature");
// Not fully supported since we don't maintain a buffer
}
/*
*
*/
public void close()
throws IOException
{
/* Note: this operation currently only stops RX on a socket that is shared
between both I/OStreams. This means that closing this stream will only shutdown
that aspect of the socket but not actually close it and free resources. Resources
will be properly freed when the socket implementation's close() is called or if
both I/OStreams are closed separately */
ZeroTier.shutdown(zfd, ZeroTier.SHUT_WR);
zfd = -1;
}
/*
*
*/
public void write(byte[] b)
throws IOException
{
int err = ZeroTier.write(zfd, b);
if (err < 0) {
throw new IOException("write(b[]), errno="+err);
}
}
/*
*
*/
public void write(byte[] b, int off, int len)
throws IOException
{
Objects.requireNonNull(b, "input byte array must not be null");
if ((off < 0) | (len < 0) | (off+len > b.length)) {
throw new IndexOutOfBoundsException("write(b,off,len)");
}
int err = ZeroTier.write_offset(zfd, b, off, len);
if (err < 0) {
throw new IOException("write(b[],off,len), errno="+err);
}
}
/*
*
*/
public void write(int b)
throws IOException
{
byte lowByte = (byte)(b & 0xFF);
int err = ZeroTier.write_byte(zfd, lowByte);
if (err < 0) {
throw new IOException("write(b), errno="+err);
}
}
}

View File

@@ -1,47 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocketAddress;
public class ZeroTierPeerDetails
{
/**
* ZeroTier address (40 bits)
*/
public long address;
/**
* Remote major version or -1 if not known
*/
public int versionMajor;
/**
* Remote minor version or -1 if not known
*/
public int versionMinor;
/**
* Remote revision or -1 if not known
*/
public int versionRev;
/**
* Last measured latency in milliseconds or -1 if unknown
*/
public int latency;
/**
* What trust hierarchy role does this device have?
*/
public int role;
/**
* Number of paths (size of paths[])
*/
public int pathCount;
/**
* Known network paths to peer
*/
public ZeroTierSocketAddress[] paths = new ZeroTierSocketAddress[ZeroTier.ZT_MAX_PEER_NETWORK_PATHS];
}

View File

@@ -1,19 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
public class ZeroTierProtoStats
{
public int xmit; /* Transmitted packets. */
public int recv; /* Received packets. */
public int fw; /* Forwarded packets. */
public int drop; /* Dropped packets. */
public int chkerr; /* Checksum error. */
public int lenerr; /* Invalid length error. */
public int memerr; /* Out of memory error. */
public int rterr; /* Routing error. */
public int proterr; /* Protocol error. */
public int opterr; /* Error in options. */
public int err; /* Misc error. */
public int cachehit;
}

View File

@@ -1,101 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTierSocket;
import java.net.*;
import javax.net.SocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.util.Locale;
import javax.net.ssl.SSLSocketFactory;
public class ZeroTierSSLSocketFactory extends SSLSocketFactory
{
private final SSLSocketFactory delegate;
/*
*
*/
public ZeroTierSSLSocketFactory(SSLSocketFactory delegate)
{
this.delegate = delegate;
}
/*
*
*/
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException
{
ZeroTierSocket zs = new ZeroTierSocket();
zs.connect((SocketAddress)new InetSocketAddress(host, port), 10);
return delegate.createSocket(zs, host, port, autoClose);
}
/*
*
*/
public Socket createSocket(Socket s, InputStream consumed, boolean autoClose)
throws IOException
{
throw new UnsupportedOperationException();
}
/*
*
*/
public Socket createSocket(InetAddress a,int b,InetAddress c,int d)
throws IOException
{
ZeroTierSocket s = new ZeroTierSocket();
return delegate.createSocket(a, b, c, d);
}
/*
*
*/
public Socket createSocket(InetAddress a,int b)
throws IOException
{
ZeroTierSocket s = new ZeroTierSocket();
return delegate.createSocket(a, b);
}
/*
*
*/
public Socket createSocket(String a,int b,InetAddress c,int d)
throws IOException
{
ZeroTierSocket s = new ZeroTierSocket();
return delegate.createSocket(a, b, c, d);
}
/*
*
*/
public Socket createSocket(String a,int b)
throws IOException
{
ZeroTierSocket s = new ZeroTierSocket();
return delegate.createSocket(a, b);
}
/*
*
*/
public String [] getSupportedCipherSuites()
{
return new String[0];
}
/*
*
*/
public String [] getDefaultCipherSuites()
{
return new String[0];
}
}

View File

@@ -1,748 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocketAddress;
import com.zerotier.libzt.ZeroTierSocketImpl;
import com.zerotier.libzt.ZeroTierSocketImplFactory;
import com.zerotier.libzt.ZeroTierInputStream;
import com.zerotier.libzt.ZeroTierOutputStream;
import java.io.*;
import java.net.*;
import java.util.Objects;
import java.nio.channels.SocketChannel;
import java.net.InetAddress;
public class ZeroTierSocket extends Socket
{
/*
* Factory designated to create the underlying ZeroTierSocket implementation
*/
static ZeroTierSocketImplFactory factory = new ZeroTierSocketImplFactory();
/*
* Underlying implementation of this ZeroTierSocket
*/
ZeroTierSocketImpl impl;
/*
* Misc. state flags
*/
private boolean created = false;
private boolean closed = false;
private boolean connected = false;
private boolean bound = false;
private boolean inputShutdown = false;
private boolean outputShutdown = false;
/*
* Creates and sets the implementation
*/
void setImpl()
{
if (factory != null) {
impl = factory.createSocketImpl();
}
if (impl != null) {
impl.setSocket(this);
}
}
/*
* Returns the underlying socket implementation
*/
private ZeroTierSocketImpl getImpl()
throws SocketException
{
if (!created) {
try {
impl.create(true);
}
catch (IOException ex) {
throw (SocketException) new SocketException().initCause(ex);
}
created = true;
}
return impl;
}
/*
* Create the underlying socket implementation
*/
void createImpl(boolean stream)
throws SocketException
{
if (impl == null) {
setImpl();
}
try {
impl.create(stream);
created = true;
}
catch (IOException ex) {
throw new SocketException(ex.getMessage());
}
}
/*
* Constructor for ZeroTierSocket
*/
public ZeroTierSocket()
throws IOException
{
this((InetAddress)null, 0, null, 0);
}
/*
* Creates an unconnected socket
*/
protected ZeroTierSocket(ZeroTierSocketImpl impl)
throws SocketException
{
this.impl = impl;
if (impl != null) {
this.impl.setSocket(this);
}
}
/*
* Constructor for ZeroTierSocket
*/
public ZeroTierSocket(InetAddress raddr, int rport, InetAddress laddr, int lport)
throws IOException
{
setImpl();
try {
if (laddr != null) {
bind(new InetSocketAddress(laddr, lport));
}
if (raddr != null) {
connect(new InetSocketAddress(raddr, rport));
}
}
catch (Exception ex)
{
try {
close();
}
catch (IOException _ex) {
ex.addSuppressed(_ex);
}
throw ex;
}
}
/*
* Constructor for ZeroTierSocket
*/
public ZeroTierSocket(InetAddress address, int port)
throws IOException
{
this(address, port, null, 0);
}
/*
* Constructor for ZeroTierSocket
*/
public ZeroTierSocket(String address, int port)
throws IOException
{
this(InetAddress.getByName(address), port, null, 0);
}
/*
* Constructor for ZeroTierSocket
*/
public ZeroTierSocket(String address, int port, InetAddress localHost, int localPort)
throws IOException
{
this(InetAddress.getByName(address), port, localHost, localPort);
}
/*
* Binds the socket to a local address
*/
public void bind(SocketAddress localAddr)
throws IOException
{
if (isSocketBound()) {
throw new SocketException("bind: ZeroTierSocket is already bound");
}
if (isSocketClosed()) {
throw new SocketException("bind: ZeroTierSocket is closed");
}
if (localAddr != null && (!(localAddr instanceof InetSocketAddress))) {
throw new IllegalArgumentException("bind: Unsupported address type");
}
InetSocketAddress addr = (InetSocketAddress)localAddr;
if (addr != null && addr.isUnresolved()) {
throw new SocketException("bind: Unresolved address");
}
if (addr == null) {
addr = new InetSocketAddress(0);
}
getImpl().bind(addr.getAddress(), addr.getPort());
bound = true;
}
/*
* Closes the socket
*/
public synchronized void close()
throws IOException
{
if (isSocketClosed()) {
return;
}
getOutputStream().flush();
impl.close();
closed = true;
}
/*
* Connects the socket to a remote address
*/
public void connect(SocketAddress remoteAddr)
throws IOException
{
connect(remoteAddr, 0);
}
/*
* Connects the socket to a remote address
*/
public void connect(SocketAddress remoteAddr, int timeout)
throws IOException
{
if (isSocketClosed()) {
throw new SocketException("connect: ZeroTierSocket is closed");
}
if (isSocketConnected()) {
throw new SocketException("connect: already connected");
}
if (remoteAddr == null) {
throw new IllegalArgumentException("connect: The address can't be null");
}
if (!(remoteAddr instanceof InetSocketAddress)) {
throw new IllegalArgumentException("connect: Unsupported address type");
}
if (timeout < 0) {
throw new IllegalArgumentException("connect: timeout cannot be negative");
}
if (!created) {
createImpl(true);
}
getImpl().connect(remoteAddr, 0);
bound = true;
connected = true;
}
/*
* Returns the associated Channel
*/
public SocketChannel getChannel()
{
System.err.println("getChannel: ZeroTierSocket does not currently support this feature");
return null;
}
/*
* Returns the address to which the socket is connected
*/
public InetAddress getInetAddress()
{
if (!isSocketConnected()) {
return null;
}
try {
return getImpl().getInetAddress();
}
catch (SocketException ex) {
// Not Reachable
}
return null;
}
/*
* Returns the input stream
*/
public ZeroTierInputStream getInputStream()
throws IOException
{
if (!isSocketConnected()) {
throw new SocketException("ZeroTierSocket is not connected");
}
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (isInputStreamShutdown()) {
throw new SocketException("ZeroTierSocket input is shutdown");
}
return getImpl().getInputStream();
}
/*
* Returns whether SO_KEEPALIVE is enabled
*/
public boolean getKeepAlive()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
return ((Boolean) getImpl().getOption(ZeroTier.SO_KEEPALIVE)).booleanValue();
}
/*
* Returns the local address to which the socket is bound
*/
public InetAddress getLocalAddress()
{
System.err.println("getLocalAddress: ZeroTierSocket does not currently support this feature");
/*
// This is for backward compatibility
if (!isSocketBound()) {
return InetAddress.anyLocalAddress();
}
InetAddress inAddr = null;
try {
inAddr = (InetAddress) getImpl().getOption(ZeroTier.SO_BINDADDR);
if (inAddr.isAnyLocalAddress()) {
inAddr = InetAddress.anyLocalAddress();
}
}
catch (Exception ex) {
// "0.0.0.0"
inAddr = InetAddress.anyLocalAddress();
}
return inAddr;
*/
return null;
}
/*
* Return the local port to which the socket is bound
*/
public int getLocalPort()
{
if (!isSocketBound()) {
return -1;
}
try {
return getImpl().getLocalPort();
}
catch(SocketException ex) {
// Unreachable
}
return -1;
}
/*
* Returns the address of the endpoint that the socket is bound to.
*/
public SocketAddress getLocalSocketAddress()
{
if (!isSocketBound()) {
return null;
}
return new InetSocketAddress(getLocalAddress(), getLocalPort());
}
/*
* Returns whether SO_OOBINLINE is enabled.
*/
public boolean getOOBInline()
throws SocketException
{
System.err.println("getOOBInline: ZeroTierSocket does not currently support this feature");
return false;
}
/*
* Returns the output stream.
*/
public ZeroTierOutputStream getOutputStream()
throws IOException
{
if (!isSocketConnected()) {
throw new SocketException("ZeroTierSocket is not connected");
}
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (isOutputStreamShutdown()) {
throw new SocketException("ZeroTierSocket output is shutdown");
}
return getImpl().getOutputStream();
}
/*
* Return the remote port to which the socket is connected
*/
public int getPort()
{
if (!isSocketConnected()) {
return 0;
}
try {
return getImpl().getPort();
}
catch (SocketException ex) {
// Not reachable
}
return -1;
}
/*
* Returns SO_RCVBUF
*/
public synchronized int getReceiveBufferSize()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
Object opt = getImpl().getOption(ZeroTier.SO_RCVBUF);
int sz = 0;
if (opt instanceof Integer) {
sz = ((Integer)opt).intValue();
}
return sz;
}
/*
* Returns the remote address to which this socket is connected
*/
public SocketAddress getRemoteSocketAddress()
{
if (!isSocketConnected()) {
return null;
}
return new InetSocketAddress(getInetAddress(), getPort());
}
/*
* Checks whether SO_REUSEADDR is enabled.
*/
public boolean getReuseAddress()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
return ((Boolean)(getImpl().getOption(ZeroTier.SO_REUSEADDR))).booleanValue();
}
/*
* Returns SO_SNDBUF.
*/
public synchronized int getSendBufferSize()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
int sz = 0;
Object opt = getImpl().getOption(ZeroTier.SO_SNDBUF);
if (opt instanceof Integer) {
sz = ((Integer)opt).intValue();
}
return sz;
}
/*
* Returns SO_LINGER.
*/
public int getSoLinger()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
Object opt = getImpl().getOption(ZeroTier.SO_LINGER);
if (opt instanceof Integer) {
return ((Integer)opt).intValue();
}
return -1;
}
/*
* Returns SO_TIMEOUT.
*/
public synchronized int getSoTimeout()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
Object opt = getImpl().getOption(ZeroTier.SO_RCVTIMEO);
if (opt instanceof Integer) {
return ((Integer)opt).intValue();
}
else {
return 0;
}
}
/*
* Checks whether TCP_NODELAY is enabled.
*/
public boolean getTcpNoDelay()
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
return ((Boolean)getImpl().getOption(ZeroTier.TCP_NODELAY)).booleanValue();
}
/*
* Gets traffic class or type-of-service in the IP header for packets sent from this Socket
*/
public int getTrafficClass()
throws SocketException
{
System.err.println("getTrafficClass: ZeroTierSocket does not currently support this feature");
return 0;
}
/*
* Returns whether or not the socket is bound to a local interface.
*/
public boolean isSocketBound()
{
return bound;
}
/*
* Returns whether or not the socket has been closed.
*/
public boolean isSocketClosed()
{
return closed;
}
/*
* Returns whether or not the socket is connected to a remote host.
*/
public boolean isSocketConnected()
{
return connected;
}
/*
* Returns whether the input aspect of the socket has been disabled.
*/
public boolean isInputStreamShutdown()
{
return inputShutdown;
}
/*
* Returns whether the output aspect of the socket has been disabled.
*/
public boolean isOutputStreamShutdown()
{
return outputShutdown;
}
/*
* Send a byte of urgent data on the socket.
*/
public void sendUrgentData(int data)
throws IOException
{
System.err.println("sendUrgentData: ZeroTierSocket does not currently support this feature");
}
/*
* Enable or disable SO_KEEPALIVE.
*/
public void setKeepAlive(boolean on)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
getImpl().setOption(ZeroTier.SO_KEEPALIVE, Boolean.valueOf(on));
}
/*
* Enable or disable SO_OOBINLINE.
*/
public void setOOBInline(boolean on)
throws SocketException
{
System.err.println("setOOBInline: ZeroTierSocket does not currently support this feature");
}
/*
* Set performance preferences.
*/
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
{
System.err.println("setPerformancePreferences: ZeroTierSocket does not currently support this feature");
}
/*
* Set SO_RCVBUF.
*/
public synchronized void setReceiveBufferSize(int size)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (size <= 0) {
throw new IllegalArgumentException("invalid receive buffer size argument");
}
getImpl().setOption(ZeroTier.SO_RCVBUF, new Integer(size));
}
/*
* Enable or disable SO_REUSEADDR.
*/
public void setReuseAddress(boolean on)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
getImpl().setOption(ZeroTier.SO_REUSEADDR, Boolean.valueOf(on));
}
/*
* Set SO_SNDBUF.
*/
public synchronized void setSendBufferSize(int size)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (size < 0) {
throw new IllegalArgumentException("size argument cannot be negative");
}
getImpl().setOption(ZeroTier.SO_SNDBUF, new Integer(size));
}
/*
* Set Socket implementation factory for all clients.
*/
public static void setSocketImplFactory(ZeroTierSocketImplFactory fact)
throws IOException
{
if (factory != null) {
throw new SocketException("ZeroTierSocket factory is already defined");
}
factory = fact;
}
/*
* Enable or disable SO_LINGER time (seconds).
*/
public void setSoLinger(boolean on, int linger)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (!on) {
getImpl().setOption(ZeroTier.SO_LINGER, new Boolean(on));
}
else {
if (linger < 0) {
throw new IllegalArgumentException("linger argument is invalid");
}
if (linger > 0xFFFF) {
linger = 0xFFFF;
}
getImpl().setOption(ZeroTier.SO_LINGER, new Integer(linger));
}
}
/*
* Enable or disable SO_TIMEOUT with the specified timeout, in milliseconds.
*/
public void setSoTimeout(int timeout)
throws SocketException
{
if (timeout < 0) {
throw new IllegalArgumentException("timeout argument cannot be negative");
}
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
getImpl().setOption(ZeroTier.SO_RCVTIMEO, new Integer(timeout));
}
/*
* Enable or disable TCP_NODELAY (Nagle's algorithm).
*/
public void setTcpNoDelay(boolean on)
throws SocketException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
getImpl().setOption(ZeroTier.TCP_NODELAY, Boolean.valueOf(on));
}
/*
* Sets traffic class or ToS.
*/
public void setTrafficClass(int tc)
throws SocketException
{
System.err.println("setTrafficClass: ZeroTierSocket does not currently support this feature");
}
/*
* Disable the input stream for this socket.
*/
public void shutdownInput()
throws IOException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (isInputStreamShutdown()) {
throw new SocketException("ZeroTierSocket input is already shutdown");
}
if (!isSocketConnected()) {
throw new SocketException("ZeroTierSocket is not connected");
}
getImpl().shutdownInput();
inputShutdown = true;
}
/*
* Disable the output stream for this socket.
*/
public void shutdownOutput()
throws IOException
{
if (isSocketClosed()) {
throw new SocketException("ZeroTierSocket is closed");
}
if (isOutputStreamShutdown()) {
throw new SocketException("ZeroTierSocket output is already shutdown");
}
if (!isSocketConnected()) {
throw new SocketException("ZeroTierSocket is not connected");
}
getImpl().shutdownOutput();
outputShutdown = true;
}
/*
* Gets the underlying implementation's file descriptor.
*/
/*
public FileDescriptor getFileDescriptor()
{
return impl.getFileDescriptor();
}
*/
}

View File

@@ -1,66 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import java.net.InetAddress;
// Designed to transport address information across the JNI boundary
public class ZeroTierSocketAddress
{
public byte[] _ip6 = new byte[16];
public byte[] _ip4 = new byte[4];
public int _family;
public int _port; // Also reused for netmask or prefix
public ZeroTierSocketAddress() {}
public ZeroTierSocketAddress(String ipStr, int port)
{
if(ipStr.contains(":")) {
_family = ZeroTier.AF_INET6;
try {
InetAddress ip = InetAddress.getByName(ipStr);
_ip6 = ip.getAddress();
}
catch (Exception e) { }
}
else if(ipStr.contains(".")) {
_family = ZeroTier.AF_INET;
try {
InetAddress ip = InetAddress.getByName(ipStr);
_ip4 = ip.getAddress();
}
catch (Exception e) { }
}
_port = port;
}
public int getPort() { return _port; }
public int getNetmask() { return _port; }
public int getPrefix() { return _port; }
public String ipString()
{
if (_family == ZeroTier.AF_INET) {
try {
InetAddress inet = InetAddress.getByAddress(_ip4);
return "" + inet.getHostAddress();
} catch (Exception e) {
System.out.println(e);
}
}
if (_family == ZeroTier.AF_INET6) {
try {
InetAddress inet = InetAddress.getByAddress(_ip6);
return "" + inet.getHostAddress();
} catch (Exception e) {
System.out.println(e);
}
}
return "";
}
public String toString() { return ipString() + ":" + _port; }
public String toCIDR() { return ipString() + "/" + _port; }
}

View File

@@ -1,51 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import java.util.Objects;
public class ZeroTierSocketFactory extends SocketFactory
{
public ZeroTierSocketFactory() { }
public static SocketFactory getDefault()
{
return null;
}
public Socket createSocket()
throws IOException, UnknownHostException
{
return new ZeroTierSocket();
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
return new ZeroTierSocket(host, port);
}
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException
{
return new ZeroTierSocket(host, port, localHost, localPort);
}
public Socket createSocket(InetAddress host, int port)
throws IOException
{
return new ZeroTierSocket(host, port);
}
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException
{
return new ZeroTierSocket(address, port, localAddress, localPort);
}
}

View File

@@ -1,771 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocketAddress;
import com.zerotier.libzt.ZeroTierInputStream;
import com.zerotier.libzt.ZeroTierOutputStream;
import com.zerotier.libzt.ZeroTierSocketOptionValue;
import java.io.*;
import java.net.*;
import java.util.Objects;
import java.lang.Object;
import java.net.SocketImpl;
import java.net.InetSocketAddress;
import java.util.Set;
import java.lang.Boolean;
import com.zerotier.libzt.ZeroTier;
public class ZeroTierSocketImpl extends SocketImpl
{
private int defaultProtocol = 0;
/*
* File descriptor from lower native layer
*/
private int zfd = -1;
private int zfd4 = -1;
private int zfd6 = -1;
/*
* Input and Output streams
*/
private ZeroTierInputStream in = new ZeroTierInputStream();
private ZeroTierOutputStream out = new ZeroTierOutputStream();
Socket socket = null;
ServerSocket serverSocket = null;
/*
* The remote address the socket is connected to
*/
protected InetAddress address;
/*
* Sets the underlying file descriptor valud for the SocketImpl as well as the Input/OutputStream
*/
private void setNativeFileDescriptor(int fd)
{
zfd = fd;
in.zfd = fd;
out.zfd = fd;
}
/*
* Various socket options that are cached from calls to setOption() before
* the socket exists.
*/
private int _so_rcvtimeo;
private boolean _so_keepalive;
private int _so_sndbuf;
private int _so_rcvbuf;
private boolean _so_reuseaddr;
private int _so_linger;
private int _so_tos;
private boolean _so_nodelay;
private void setCachedSocketOptions(int fd)
{
if (fd < 0) {
return;
}
// If we previously received a setSoTimeout() call but were unable to process it due
// to the fact that the underlying socket didn't even exist yet, do so now.
int err = 0;
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue();
try {
// SO_TIMEOUT
if (_so_rcvtimeo > 0) {
optval.isInteger = true;
optval.isBoolean = false;
optval.integerValue = ((Integer)_so_rcvtimeo).intValue();
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_RCVTIMEO, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_RCVTIMEO");
}
}
// SO_KEEPALIVE
if (_so_keepalive == true) {
optval.isInteger = false;
optval.isBoolean = true;
optval.booleanValue = ((Boolean)_so_keepalive).booleanValue() ? true : false;
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_KEEPALIVE, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_KEEPALIVE");
}
}
// SO_SNDBUF
if (_so_sndbuf > 0) {
optval.isInteger = true;
optval.isBoolean = false;
optval.integerValue = ((Integer)_so_sndbuf).intValue();
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_SNDBUF, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_SNDBUF");
}
}
// SO_RCVBUF
if (_so_rcvbuf > 0) {
optval.isInteger = true;
optval.isBoolean = false;
optval.integerValue = ((Integer)_so_rcvbuf).intValue();
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_RCVBUF, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_RCVBUF");
}
}
// SO_REUSEADDR
if (_so_reuseaddr == true) {
optval.isInteger = false;
optval.isBoolean = true;
optval.booleanValue = ((Boolean)_so_reuseaddr).booleanValue() ? true : false;
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_REUSEADDR, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_REUSEADDR");
}
}
// SO_LINGER
if (_so_linger > 0) {
optval.isInteger = true;
optval.isBoolean = false;
optval.integerValue = ((Integer)_so_linger).intValue();
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_LINGER, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_LINGER");
}
}
// IP_TOS
if (_so_tos > 0) {
optval.isInteger = true;
optval.isBoolean = false;
optval.integerValue = ((Integer)_so_tos).intValue();
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.IP_TOS, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached IP_TOS");
}
}
// TCP_NODELAY
if (_so_nodelay == true) {
optval.isInteger = false;
optval.isBoolean = true;
optval.booleanValue = ((Boolean)_so_nodelay).booleanValue() ? true : false;
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.TCP_NODELAY, optval)) < 0) {
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached TCP_NODELAY");
}
}
}
catch (Exception e) {
System.err.println(e);
}
}
/*
* Constructor which creates a new ZeroTierSocketImpl
*/
public ZeroTierSocketImpl()
{
if ((zfd > -1) | (zfd4 > -1) | (zfd6 > -1)) { return; }
try {
create(true);
} catch (Exception x) {
System.err.println("error creating ZeroTierSocketImpl instance: " + x);
}
in.zfd = zfd;
out.zfd = zfd;
}
/*
* Constructor to be called when an underlying ZeroTier socket already exists (does not create a new ZeroTierSocketImpl)
*/
public ZeroTierSocketImpl(int fd) {
setNativeFileDescriptor(fd);
}
/*
* Creates a new ZeroTier socket in the native layer
*/
protected void create(boolean stream)
throws IOException
{
/*
* The native-layer socket is only created once a connect/bind call is made, this is due to the fact
* that beforehand we have no way to determine whether we should create an AF_INET or AF_INET6 socket,
* as a result, this method intentionally does nothing.
*/
}
/*
* Creates the underlying libzt socket.
*
* This does the real work that can't be done in the constructor. This is because the socket address type
* isn't known until a connect() or bind() request is given. Additionally we cache the value provided by any
* setSoTimeout() calls and implement it immediately after creation.
*/
private void createAppropriateSocketImpl(InetAddress addr)
throws IOException
{
if ((zfd > -1) | (zfd4 > -1) | (zfd6 > -1)) {
return; // Socket already created
}
if(addr instanceof Inet4Address) {
if ((zfd4 = ZeroTier.socket(ZeroTier.AF_INET, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) {
throw new IOException("socket(), errno="+zfd4+", see: libzt/ext/lwip/src/include/errno.h");
}
setCachedSocketOptions(zfd4);
}
/*
* Since Java creates sockets capable of handling IPV4 and IPV6, we must simulate this. We do this by
* creating two sockets (one of each type)
*/
if(addr instanceof Inet6Address) {
if ((zfd4 = ZeroTier.socket(ZeroTier.AF_INET, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) {
throw new IOException("socket(), errno="+zfd4+", see: libzt/ext/lwip/src/include/errno.h");
}
if ((zfd6 = ZeroTier.socket(ZeroTier.AF_INET6, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) {
throw new IOException("socket(), errno="+zfd6+", see: libzt/ext/lwip/src/include/errno.h");
}
setCachedSocketOptions(zfd4);
setCachedSocketOptions(zfd6);
}
}
/*
* Return the remote address the socket is connected to
*/
protected InetAddress getInetAddress()
{
return address;
}
/*
* Connects the socket to a remote address
*/
protected void connect(String host, int port)
throws IOException
{
// TODO: Refactor and consolidate the connect() logic for all three methods
createAppropriateSocketImpl(InetAddress.getByName(host));
if ((zfd4 < 0) & (zfd6 < 0)) {
throw new IOException("invalid fd");
}
int err;
InetAddress address = InetAddress.getByName(host);
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(host, port);
if (address instanceof Inet4Address) {
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) {
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd4);
}
if (address instanceof Inet6Address) {
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) {
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd6);
}
super.port = port;
}
/*
* Connects the socket to a remote address
*/
protected void connect(InetAddress address, int port)
throws IOException
{
// TODO: Refactor and consolidate the connect() logic for all three methods
createAppropriateSocketImpl(address);
if ((zfd4 < 0) & (zfd6 < 0)) {
throw new IOException("invalid fd");
}
int err;
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(address.getHostAddress(), port);
if (address instanceof Inet4Address) {
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) {
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd4);
}
if (address instanceof Inet6Address) {
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) {
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd6);
}
super.port = port;
}
/*
* Connects the socket to a remote address
*/
protected void connect(SocketAddress address, int timeout)
throws IOException
{
// TODO: Refactor and consolidate the connect() logic for all three methods
//System.out.println("host="+((InetSocketAddress)address).getHostString()+", port="+((InetSocketAddress)address).getPort() + ", timeout="+timeout);
createAppropriateSocketImpl(((InetSocketAddress)address).getAddress());
if ((zfd4 < 0) & (zfd6 < 0)) {
throw new IOException("invalid fd");
}
ZeroTierSocketAddress zt_addr = null;
int err;
int port = ((InetSocketAddress)address).getPort();
if (((InetSocketAddress)address).getAddress() instanceof Inet4Address) {
zt_addr = new ZeroTierSocketAddress(((InetSocketAddress)address).getHostString(), ((InetSocketAddress)address).getPort());
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) {
throw new IOException("connect("+zfd4+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd4);
}
if (((InetSocketAddress)address).getAddress() instanceof Inet6Address) {
zt_addr = new ZeroTierSocketAddress(((InetSocketAddress)address).getHostString(), ((InetSocketAddress)address).getPort());
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) {
throw new IOException("connect("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
setNativeFileDescriptor(zfd6);
}
super.port = port;
}
/*
* Binds the socket to a local address.
*
* If this gets a bind() request on [::] it will create a both an IPv4 and an IPv6
* socket. This is because we might receive a subsequent listen() and accept() request
* and want to accept an IPv6 connection. (or) we may get a connect() request with
* an IPv4 address. In the latter case we must abandon the IPv6 socket and use the IPv4
* socket exclusively.
*/
protected void bind(InetAddress host, int port)
throws IOException
{
createAppropriateSocketImpl(host);
/*
After this point we may have either a) created a single IPv4 socket, or b) created
an IPv4 and IPv6 socket in anticipation of either verion being used
*/
//System.out.println("host="+host.toString()+", port="+port);
int err;
if ((zfd < 0) & (zfd4 < 0) & (zfd6 < 0)) {
throw new IOException("invalid fd");
}
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(host.getHostAddress(), port);
if (zfd6 > -1) {
// Since an IPv6 socket and accept IPv4 connections we will only bind to this address
if ((err = ZeroTier.bind(zfd6, zt_addr)) < 0) {
throw new IOException("bind("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
super.localport = port;
return;
}
if (zfd4 > -1) {
// Otherwise, just bind to the regular IPv4 address
if ((err = ZeroTier.bind(zfd4, zt_addr)) < 0) {
throw new IOException("bind("+zfd4+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
super.localport = port;
return;
}
}
/*
* Puts the socket into a listening state.
*
* We listen on the IPv6 socket since it can listen for IPv4 connections
*/
protected void listen(int backlog)
throws IOException
{
int err;
if ((zfd6 < 0) | (backlog < 0)) {
throw new IOException("invalid fd and/or backlog");
}
if ((err = ZeroTier.listen(zfd6, backlog)) < 0) {
throw new IOException("listen("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h");
}
}
/*
* Accepts an incoming connection.
*
* We accept on the IPv6 socket since it can accept IPv4 connections
*/
protected void accept(SocketImpl si)
throws IOException
{
if (zfd6 < 0) {
throw new IOException("invalid fd");
}
int accetpedFd = -1;
ZeroTierSocketAddress addr = new ZeroTierSocketAddress();
if ((accetpedFd = ZeroTier.accept(zfd6, addr)) < 0) {
throw new IOException("accept("+zfd6+"), errno="+accetpedFd+", see: libzt/ext/lwip/src/include/errno.h");
}
// Give the new socket fd from the native layer to the new unconnected ZeroTierSocketImpl
((ZeroTierSocketImpl)si).setFileDescriptor(accetpedFd);
}
/*
* Returns the input stream for this socket
*/
protected ZeroTierInputStream getInputStream()
throws IOException
{
if (in == null) {
throw new IOException();
}
return in;
}
/*
* Returns the output stream for this socket
*/
protected ZeroTierOutputStream getOutputStream()
throws IOException
{
if (out == null) {
throw new IOException();
}
return out;
}
/*
* Returns the remote port to which this socket is connected
*/
protected int getPort()
{
return super.port;
}
/*
* Returns the local port to which this socket is bound
*/
protected int getLocalPort()
{
return super.localport;
}
/*
* Returns whether this socket implementation supports urgent data (hint: it doesn't)
*/
protected boolean supportsUrgentData()
{
return false;
}
/*
*
*/
void setSocket(ZeroTierSocket soc)
{
this.socket = soc;
}
/*
*
*/
Socket getSocket()
{
return socket;
}
/*
*
*/
/*
void setServerSocket(ZeroTierServerSocket soc)
{
this.serverSocket = soc;
}
*/
/*
*
*/
ServerSocket getServerSocket()
{
return serverSocket;
}
/*
* Return the number of bytes that can be read from the socket without blocking
*/
protected int available()
throws IOException
{
// TODO
return 0;
}
/*
* Closes the socket
*/
protected void close()
throws IOException
{
if (zfd > -1) {
ZeroTier.close(zfd);
}
if (zfd4 > -1) {
ZeroTier.close(zfd4);
}
if (zfd6 > -1) {
ZeroTier.close(zfd6);
}
}
/*
* Send one byte of urgent data on the socket
*/
protected void sendUrgentData(int data)
throws IOException
{
System.err.println("sendUrgentData: ZeroTierSocketImpl does not currently support this feature");
}
/*
* Gets some specified socket option
*/
public Object getOption(int optID)
throws SocketException
{
// Call native layer
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue();
int option = -1;
int level = -1;
if (zfd < 0) { // If we haven't committed to a socket version yet, cache the value
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) {
return Integer.valueOf(_so_rcvtimeo);
}
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) {
return Boolean.valueOf(_so_keepalive);
}
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) {
return Integer.valueOf(_so_sndbuf);
}
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) {
return Integer.valueOf(_so_rcvbuf);
}
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) {
return Boolean.valueOf(_so_reuseaddr);
}
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) {
return Integer.valueOf(_so_linger);
}
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) {
return Integer.valueOf(_so_tos);
}
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) {
return Boolean.valueOf(_so_nodelay);
}
}
else {
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) {
option = ZeroTier.SO_RCVTIMEO;
level = ZeroTier.SOL_SOCKET;
}
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) {
option = ZeroTier.SO_KEEPALIVE;
level = ZeroTier.SOL_SOCKET;
}
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) {
option = ZeroTier.SO_SNDBUF;
level = ZeroTier.SOL_SOCKET;
}
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) {
option = ZeroTier.SO_RCVBUF;
level = ZeroTier.SOL_SOCKET;
}
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) {
option = ZeroTier.SO_REUSEADDR;
level = ZeroTier.SOL_SOCKET;
}
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) {
option = ZeroTier.SO_LINGER;
level = ZeroTier.SOL_SOCKET;
}
// IP
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) {
option = ZeroTier.IP_TOS;
level = ZeroTier.IPPROTO_IP;
}
// TCP
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) {
option = ZeroTier.TCP_NODELAY;
level = ZeroTier.IPPROTO_TCP;
}
ZeroTier.getsockopt(zfd, level, option, optval);
// Convert native layer's response into Java object of some sort
if (optval.isBoolean) {
return Boolean.valueOf(optval.booleanValue);
}
if (optval.isInteger) {
return Integer.valueOf(optval.integerValue);
}
}
return null;
}
/*
* Sets a socket option to a specified value. This method should be able to handle SocketOptions values
* as well as native ZeroTier.* options
*/
public void setOption(int optID, Object value)
throws SocketException
{
if (value == null) {
throw new UnsupportedOperationException();
}
int option = -1;
int level = -1;
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue();
if (zfd < 0) { // If we haven't committed to a socket version yet, cache the value
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) {
_so_rcvtimeo = ((Integer)value).intValue(); return;
}
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) {
_so_keepalive = ((Boolean)value).booleanValue() ? true : false; return;
}
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) {
_so_sndbuf = ((Integer)value).intValue(); return;
}
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) {
_so_rcvbuf = ((Integer)value).intValue(); return;
}
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) {
_so_reuseaddr = ((Boolean)value).booleanValue() ? true : false; return;
}
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) {
_so_linger = ((Integer)value).intValue(); return;
}
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) {
_so_tos = ((Integer)value).intValue(); return;
}
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) {
_so_nodelay = ((Boolean)value).booleanValue() ? true : false; return;
}
}
else {
// SOL
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) {
option = ZeroTier.SO_RCVTIMEO;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isInteger = true;
optval.integerValue = ((Integer)value).intValue();
}
}
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) {
option = ZeroTier.SO_KEEPALIVE;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isBoolean = true;
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false;
}
}
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) {
option = ZeroTier.SO_SNDBUF;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isInteger = true;
optval.integerValue = ((Integer)value).intValue();
}
}
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) {
option = ZeroTier.SO_RCVBUF;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isInteger = true;
optval.integerValue = ((Integer)value).intValue();
}
}
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) {
option = ZeroTier.SO_REUSEADDR;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isBoolean = true;
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false;
}
}
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) {
option = ZeroTier.SO_LINGER;
level = ZeroTier.SOL_SOCKET;
if (value instanceof Integer) {
optval.isInteger = true;
optval.integerValue = ((Integer)value).intValue();
}
}
// IP
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) {
option = ZeroTier.IP_TOS;
level = ZeroTier.IPPROTO_IP;
if (value instanceof Integer) {
optval.isInteger = true;
optval.integerValue = ((Integer)value).intValue();
}
}
// TCP
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) {
option = ZeroTier.TCP_NODELAY;
level = ZeroTier.IPPROTO_TCP;
if (value instanceof Integer) {
optval.isBoolean = true;
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false;
}
}
if (option < 0) { // No option was properly set
//throw new UnsupportedOperationException();
}
ZeroTier.setsockopt(zfd, level, option, optval);
}
}
/*
* Disables the input aspect of the socket
*/
public void shutdownInput()
{
ZeroTier.shutdown(zfd, ZeroTier.SHUT_RD);
// Alternatively: getInputStream().close();
}
/*
* Disables the output aspect of the socket
*/
public void shutdownOutput()
{
ZeroTier.shutdown(zfd, ZeroTier.SHUT_WR);
// Alternatively: getOutputStream().close();
}
/*
* Sets the file descriptor
*/
public void setFileDescriptor(int fd)
{
zfd = fd;
}
/*
* Resets the socket
*/
void reset()
throws IOException
{
localport = 0;
address = null;
port = 0;
}
/*
public FileDescriptor getFileDescriptor()
{
// TODO: Should probably remove this for production
System.out.println("getFileDescriptor(), zfd="+zfd);
ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(zfd);
return pfd.getFileDescriptor();
}
*/
}

View File

@@ -1,29 +0,0 @@
package com.zerotier.libzt;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocketImpl;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import java.net.SocketImplFactory;
import java.util.Objects;
public class ZeroTierSocketImplFactory implements SocketImplFactory
{
/*
* Does nothing
*/
public ZeroTierSocketImplFactory() { }
/*
* Produces a ZeroTierSocketImpl
*/
public ZeroTierSocketImpl createSocketImpl()
{
return new ZeroTierSocketImpl();
}
}

View File

@@ -1,14 +0,0 @@
package com.zerotier.libzt;
public class ZeroTierSocketOptionValue
{
public boolean isBoolean = false;
public boolean booleanValue;
public boolean isInteger = false;
public int integerValue;
public boolean isTimeval = false;
public int tv_sec; // seconds
public int tv_usec; // microseconds
}