removed all contents
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
Source Directory Structure
|
||||
====
|
||||
|
||||
`wrappers` - Example bindings of the ZeroTierSDK Sockets API to your favorite native languages
|
||||
|
||||
`stack_drivers` - Drivers to mate various network stacks to the ZeroTier tap interface
|
||||
|
||||
See [here](../docs/technical.md) for a technical discussion on this all works.
|
||||
159
src/debug.h
159
src/debug.h
@@ -1,159 +0,0 @@
|
||||
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _SDK_DEBUG_H_
|
||||
#define _SDK_DEBUG_H_
|
||||
|
||||
#define DEBUG_LEVEL 0 // Set this to adjust what you'd like to see in the debug traces
|
||||
|
||||
#define MSG_ERROR 1 // Errors
|
||||
#define MSG_TRANSFER 2 // RX/TX specific statements
|
||||
#define MSG_INFO 3 // Information which is generally useful to any developer
|
||||
#define MSG_EXTRA 4 // If nothing in your world makes sense
|
||||
#define MSG_FLOW 5 // High-level flow messages
|
||||
|
||||
#define __SHOW_FILENAMES__ true
|
||||
#define __SHOW_COLOR__ true
|
||||
|
||||
// Colors
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#if defined(__SHOW_COLOR__) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__)
|
||||
#define RED "\x1B[31m"
|
||||
#define GRN "\x1B[32m"
|
||||
#define YEL "\x1B[33m"
|
||||
#define BLU "\x1B[34m"
|
||||
#define MAG "\x1B[35m"
|
||||
#define CYN "\x1B[36m"
|
||||
#define WHT "\x1B[37m"
|
||||
#define RESET "\x1B[0m"
|
||||
#else
|
||||
#define RED
|
||||
#define GRN
|
||||
#define YEL
|
||||
#define BLU
|
||||
#define MAG
|
||||
#define CYN
|
||||
#define WHT
|
||||
#define RESET
|
||||
#endif
|
||||
|
||||
// filenames
|
||||
#if __SHOW_FILENAMES__
|
||||
#if __SHOW_FULL_FILENAME_PATH__
|
||||
#define __FILENAME__ __FILE__ // show the entire mess
|
||||
#else
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // shorten
|
||||
#endif
|
||||
#else
|
||||
#define __FILENAME__ // omit filename
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#define THREAD_ID (long)getpid()
|
||||
#elif __APPLE__
|
||||
#define THREAD_ID (long)syscall(SYS_thread_selfid)
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#define LOG_TAG "ZTSDK"
|
||||
#endif
|
||||
|
||||
//#if defined(SDK_DEBUG)
|
||||
#if DEBUG_LEVEL >= MSG_ERROR
|
||||
#define DEBUG_ERROR(fmt, args...) fprintf(stderr, RED "ZT_ERROR[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#else
|
||||
#define DEBUG_ERROR(fmt, args...)
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_INFO
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:%20s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#define DEBUG_BLANK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:" fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#define DEBUG_ATTN(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_INFO : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#define DEBUG_STACK(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_STACK: %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#else
|
||||
#define DEBUG_INFO(fmt, args...) fprintf(stderr, "ZT_INFO [%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#define DEBUG_ATTN(fmt, args...) fprintf(stderr, CYN "ZT_ATTN [%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#define DEBUG_STACK(fmt, args...) fprintf(stderr, YEL "ZT_STACK[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#define DEBUG_BLANK(fmt, args...) fprintf(stderr, "ZT_INFO [%ld] : %14s:%4d:" fmt "\n", THREAD_ID, __FILENAME__, __LINE__, ##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_INFO(fmt, args...)
|
||||
#define DEBUG_BLANK(fmt, args...)
|
||||
#define DEBUG_ATTN(fmt, args...)
|
||||
#define DEBUG_STACK(fmt, args...)
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_TRANSFER
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_TRANS(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_TRANS : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#else
|
||||
#define DEBUG_TRANS(fmt, args...) fprintf(stderr, GRN "ZT_TRANS[%ld] : %14s:%4d:%25s: " fmt "\n" RESET, THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_TRANS(fmt, args...)
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_EXTRA
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_EXTRA(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_EXTRA : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#else
|
||||
#define DEBUG_EXTRA(fmt, args...) fprintf(stderr, "ZT_EXTRA[%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_EXTRA(fmt, args...)
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_FLOW
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_FLOW(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "ZT_FLOW : %14s:%4d:%25s: " fmt "\n", __FILENAME__, __LINE__, __FUNCTION__, ##args))
|
||||
#else
|
||||
#define DEBUG_FLOW(fmt, args...) fprintf(stderr, "ZT_FLOW [%ld] : %14s:%4d:%25s: " fmt "\n", THREAD_ID, __FILENAME__, __LINE__, __FUNCTION__, ##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_FLOW(fmt, args...)
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _SDK_DEBUG_H_
|
||||
54
src/defs.h
54
src/defs.h
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#define SDK_MTU 1200//ZT_MAX_MTU // 2800, usually
|
||||
|
||||
#define UNIX_SOCK_BUF_SIZE 1024*1024
|
||||
#define ZT_PHY_POLL_INTERVAL 50 // in ms
|
||||
|
||||
// picoTCP
|
||||
#define MAX_PICO_FRAME_RX_BUF_SZ ZT_MAX_MTU * 128
|
||||
|
||||
// General
|
||||
// TCP Buffer sizes
|
||||
#define DEFAULT_TCP_TX_BUF_SZ 1024 * 1024
|
||||
#define DEFAULT_TCP_RX_BUF_SZ 1024 * 1024
|
||||
|
||||
// TCP RX/TX buffer soft boundaries
|
||||
#define DEFAULT_TCP_TX_BUF_SOFTMAX DEFAULT_TCP_TX_BUF_SZ * 0.80
|
||||
#define DEFAULT_TCP_TX_BUF_SOFTMIN DEFAULT_TCP_TX_BUF_SZ * 0.20
|
||||
#define DEFAULT_TCP_RX_BUF_SOFTMAX DEFAULT_TCP_RX_BUF_SZ * 0.80
|
||||
#define DEFAULT_TCP_RX_BUF_SOFTMIN DEFAULT_TCP_RX_BUF_SZ * 0.20
|
||||
|
||||
// UDP Buffer sizes (should be about the size of your MTU)
|
||||
#define DEFAULT_UDP_TX_BUF_SZ ZT_MAX_MTU
|
||||
#define DEFAULT_UDP_RX_BUF_SZ ZT_MAX_MTU * 10
|
||||
|
||||
// lwIP
|
||||
#define APPLICATION_POLL_FREQ 2
|
||||
#define ZT_LWIP_TCP_TIMER_INTERVAL 50
|
||||
#define STATUS_TMR_INTERVAL 500 // How often we check connection statuses (in ms)
|
||||
587
src/intercept.c
587
src/intercept.c
@@ -1,587 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#if defined(SDK_INTERCEPT)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <strings.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/resource.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/errno.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/net.h>
|
||||
#endif
|
||||
|
||||
#include "sdk.h"
|
||||
#include "debug.h"
|
||||
#include "rpc.h"
|
||||
|
||||
pthread_key_t thr_id_key;
|
||||
|
||||
// externs common between SDK_Intercept and SDK_Socket from SDK.h
|
||||
#if defined(__linux__)
|
||||
int (*realaccept4)(ACCEPT4_SIG) = 0;
|
||||
#if !defined(__ANDROID__)
|
||||
int (*realsyscall)(SYSCALL_SIG) = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
int (*realbind)(BIND_SIG) = 0;
|
||||
int (*realsendmsg)(SENDMSG_SIG) = 0;
|
||||
ssize_t (*realsendto)(SENDTO_SIG) = 0;
|
||||
int (*realrecvmsg)(RECVMSG_SIG) = 0;
|
||||
int (*realrecvfrom)(RECVFROM_SIG) = 0;
|
||||
#endif
|
||||
int (*realconnect)(CONNECT_SIG) = 0;
|
||||
int (*realaccept)(ACCEPT_SIG) = 0;
|
||||
int (*reallisten)(LISTEN_SIG) = 0;
|
||||
int (*realsocket)(SOCKET_SIG) = 0;
|
||||
int (*realsetsockopt)(SETSOCKOPT_SIG) = 0;
|
||||
int (*realgetsockopt)(GETSOCKOPT_SIG) = 0;
|
||||
int (*realclose)(CLOSE_SIG);
|
||||
int (*realgetsockname)(GETSOCKNAME_SIG) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------- Get Original socket API pointers -----------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
extern void load_symbols()
|
||||
{
|
||||
DEBUG_EXTRA("");
|
||||
|
||||
#if defined(__linux__)
|
||||
realaccept4 = dlsym(RTLD_NEXT, "accept4");
|
||||
#if !defined(__ANDROID__)
|
||||
realsyscall = dlsym(RTLD_NEXT, "syscall");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
realsetsockopt = (int(*)(SETSOCKOPT_SIG))dlsym(RTLD_NEXT, "setsockopt");
|
||||
realgetsockopt = (int(*)(GETSOCKOPT_SIG))dlsym(RTLD_NEXT, "getsockopt");
|
||||
realsocket = (int(*)(SOCKET_SIG))dlsym(RTLD_NEXT, "socket");
|
||||
realconnect = (int(*)(CONNECT_SIG))dlsym(RTLD_NEXT, "connect");
|
||||
realaccept = (int(*)(ACCEPT_SIG))dlsym(RTLD_NEXT, "accept");
|
||||
reallisten = (int(*)(LISTEN_SIG))dlsym(RTLD_NEXT, "listen");
|
||||
realclose = (int(*)(CLOSE_SIG))dlsym(RTLD_NEXT, "close");
|
||||
realgetsockname = (int(*)(GETSOCKNAME_SIG))dlsym(RTLD_NEXT, "getsockname");
|
||||
#if !defined(__ANDROID__)
|
||||
realbind = (int(*)(BIND_SIG))dlsym(RTLD_NEXT, "bind");
|
||||
realsendto = (ssize_t(*)(int, const void *, size_t, int, const struct sockaddr *, socklen_t))dlsym(RTLD_NEXT, "sendto");
|
||||
realrecvfrom = (int(*)(RECVFROM_SIG))dlsym(RTLD_NEXT, "recvfrom");
|
||||
realrecvmsg = (int(*)(RECVMSG_SIG))dlsym(RTLD_NEXT, "recvmsg");
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------- Intercept Setup ------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// Return whether 'intercept' API is enabled for this thread
|
||||
|
||||
bool check_intercept_enabled() {
|
||||
if(!realconnect){
|
||||
load_symbols();
|
||||
}
|
||||
#if defined(SDK_BUNDLED)
|
||||
// The reasoning for this check is that if you've built the SDK with SDK_BUNDLE=1, then
|
||||
// you've included a full ZeroTier service in the same binary as your intercept, and we
|
||||
// don't want to run ZeroTier network API calls through the intercept, so we must specify
|
||||
// which threads should be intercepted manually
|
||||
void *spec = pthread_getspecific(thr_id_key);
|
||||
int thr_id = spec != NULL ? *((int*)spec) : -1;
|
||||
return thr_id == INTERCEPT_ENABLED;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------- connected_to_service() -----------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// Check whether or not the socket is mapped to the service. We
|
||||
// need to know if this is a regular AF_LOCAL socket or an end of a socketpair
|
||||
// that the service uses. We don't want to keep state in the intercept, so
|
||||
// we simply ask the service via an RPC
|
||||
|
||||
int connected_to_service(int sockfd)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof addr;
|
||||
struct sockaddr_un * addr_un;
|
||||
getpeername(sockfd, (struct sockaddr*)&addr, &len);
|
||||
if (addr.ss_family == AF_LOCAL || addr.ss_family == AF_LOCAL) {
|
||||
addr_un = (struct sockaddr_un*)&addr;
|
||||
return strcmp(addr_un->sun_path, api_netpath) == 0;
|
||||
}
|
||||
DEBUG_ERROR("not connected to service");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ sendto() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const void *buf, size_t len, int flags,
|
||||
// const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
ssize_t sendto(SENDTO_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d, len=%d", fd, (int)len);
|
||||
if (!check_intercept_enabled())
|
||||
return realsendto(fd, buf, len, flags, addr, addrlen);
|
||||
return zts_sendto(fd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- sendmsg() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct msghdr *msg, int flags
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
ssize_t sendmsg(SENDMSG_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
//if(!check_intercept_enabled())
|
||||
return realsendmsg(fd, msg, flags);
|
||||
zts_sendmsg(fd, msg, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- recvfrom() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, void *restrict buf, size_t len, int flags, struct sockaddr
|
||||
// *restrict addr, socklen_t *restrict addrlen
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
ssize_t recvfrom(RECVFROM_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
//if(!check_intercept_enabled())
|
||||
// return realrecvfrom(fd, buf, len, flags, addr, addrlen);
|
||||
return zts_recvfrom(fd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- recvmsg() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct msghdr *msg, int flags
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
ssize_t recvmsg(RECVMSG_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
//if(!check_intercept_enabled())
|
||||
return realrecvmsg(fd, msg, flags);
|
||||
return zts_recvmsg(fd, msg, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------------- setsockopt() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int level, int optname, const void *optval, socklen_t optlen
|
||||
|
||||
int setsockopt(SETSOCKOPT_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
if (!check_intercept_enabled())
|
||||
return realsetsockopt(fd, level, optname, optval, optlen);
|
||||
#if defined(__linux__)
|
||||
if(level == SOL_IPV6 && optname == IPV6_V6ONLY)
|
||||
return 0;
|
||||
if(level == SOL_IP && (optname == IP_TTL || optname == IP_TOS))
|
||||
return 0;
|
||||
#endif
|
||||
if(level == IPPROTO_TCP || (level == SOL_SOCKET && optname == SO_KEEPALIVE))
|
||||
return 0;
|
||||
if(realsetsockopt(fd, level, optname, optval, optlen) < 0)
|
||||
perror("setsockopt():\n");
|
||||
return zts_setsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------------- getsockopt() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int level, int optname, void *optval, socklen_t *optlen
|
||||
|
||||
int getsockopt(GETSOCKOPT_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
if (!check_intercept_enabled() || !connected_to_service(fd))
|
||||
return realgetsockopt(fd, level, optname, optval, optlen);
|
||||
return zts_getsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- socket() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int socket_family, int socket_type, int protocol
|
||||
|
||||
int socket(SOCKET_SIG)
|
||||
{
|
||||
DEBUG_ATTN();
|
||||
int err;
|
||||
if (!check_intercept_enabled() && socket_type) {
|
||||
if((err = realsocket(socket_family, socket_type, protocol)) < 0) {
|
||||
perror("socket:\n");
|
||||
}
|
||||
else {
|
||||
DEBUG_BLANK("realsocket(): fd=%d", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
// If the socket type is LOCAL, we don't want to handle it, pass to system
|
||||
if(socket_family == AF_LOCAL
|
||||
#if defined(__linux__)
|
||||
|| socket_family == AF_NETLINK
|
||||
#endif
|
||||
|| socket_family == AF_UNIX) {
|
||||
err = realsocket(socket_family, socket_type, protocol);
|
||||
DEBUG_BLANK("realsocket(): fd=%d", err);
|
||||
return err;
|
||||
}
|
||||
return zts_socket(socket_family, socket_type, protocol);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- connect() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
int connect(CONNECT_SIG)
|
||||
{
|
||||
DEBUG_ATTN("fd=%d", fd);
|
||||
struct sockaddr_in *connaddr;
|
||||
connaddr = (struct sockaddr_in *)addr;
|
||||
if(addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) {
|
||||
struct sockaddr_storage storage;
|
||||
memcpy(&storage, addr, addrlen);
|
||||
struct sockaddr_un *s_un = (struct sockaddr_un*)&storage;
|
||||
DEBUG_INFO("addr=%s", s_un->sun_path);
|
||||
}
|
||||
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
if(addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *connaddr = (struct sockaddr_in *)addr;
|
||||
inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN);
|
||||
sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr->sin_port));
|
||||
}
|
||||
if(addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr;
|
||||
inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN);
|
||||
sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr6->sin6_port));
|
||||
}
|
||||
DEBUG_INFO("addr=%s", addrstr);
|
||||
|
||||
if(!check_intercept_enabled())
|
||||
return realconnect(fd, addr, addrlen);
|
||||
|
||||
// Check that this is a valid fd
|
||||
/*
|
||||
if(fcntl(fd, F_GETFD) < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
// Check that it is a socket
|
||||
int sock_type;
|
||||
socklen_t sock_type_len = sizeof(sock_type);
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) {
|
||||
errno = ENOTSOCK;
|
||||
return -1;
|
||||
}
|
||||
#if defined(__linux__)
|
||||
// Check family
|
||||
if (connaddr->sin_family < 0 || connaddr->sin_family >= NPROTO){
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
// make sure we don't touch any standard outputs
|
||||
if(fd == 0 || fd == 1 || fd == 2)
|
||||
return(realconnect(fd, addr, addrlen));
|
||||
|
||||
if(addr != NULL && (connaddr->sin_family == AF_LOCAL
|
||||
#if defined(__linux__)
|
||||
|| connaddr->sin_family == PF_NETLINK
|
||||
|| connaddr->sin_family == AF_NETLINK
|
||||
#endif
|
||||
|| connaddr->sin_family == AF_UNIX)) {
|
||||
return realconnect(fd, addr, addrlen);
|
||||
}
|
||||
return zts_connect(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ bind() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
int bind(BIND_SIG)
|
||||
{
|
||||
DEBUG_ATTN("fd=%d", fd);
|
||||
// make sure we don't touch any standard outputs
|
||||
if(fd == 0 || fd == 1 || fd == 2)
|
||||
return(realbind(fd, addr, addrlen));
|
||||
|
||||
// TODO: Revisit
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
if(addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *connaddr = (struct sockaddr_in *)addr;
|
||||
inet_ntop(AF_INET, &(connaddr->sin_addr), addrstr, INET_ADDRSTRLEN);
|
||||
sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr->sin_port));
|
||||
}
|
||||
if(addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *connaddr6 = (struct sockaddr_in6 *)addr;
|
||||
inet_ntop(AF_INET6, &(connaddr6->sin6_addr), addrstr, INET6_ADDRSTRLEN);
|
||||
sprintf(addrstr, "%s:%d", addrstr, ntohs(connaddr6->sin6_port));
|
||||
}
|
||||
DEBUG_INFO("addr=%s", addrstr);
|
||||
|
||||
if(addr->sa_family == AF_LOCAL
|
||||
#if defined(__linux__)
|
||||
|| addr->sa_family == AF_NETLINK
|
||||
#endif
|
||||
|| addr->sa_family == AF_UNIX) {
|
||||
int err = realbind(fd, addr, addrlen);
|
||||
DEBUG_BLANK("realbind(): err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int sock_type;
|
||||
socklen_t sock_type_len = sizeof(sock_type);
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) {
|
||||
errno = ENOTSOCK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise, perform usual intercept logic
|
||||
if (!check_intercept_enabled())
|
||||
return realbind(fd, addr, addrlen);
|
||||
|
||||
// Check that this is a valid fd
|
||||
/*
|
||||
if(fcntl(fd, F_GETFD) < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
// Check that it is a socket
|
||||
int opt = -1;
|
||||
socklen_t opt_len;
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) {
|
||||
errno = ENOTSOCK;
|
||||
return -1;
|
||||
}
|
||||
return zts_bind(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- accept4() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct sockaddr *addr, socklen_t *addrlen, int flags
|
||||
|
||||
#if defined(__linux__)
|
||||
int accept4(ACCEPT4_SIG) {
|
||||
DEBUG_ATTN("fd=%d", fd);
|
||||
return zts_accept4(fd, addr, addrlen, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- accept() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd struct sockaddr *addr, socklen_t *addrlen
|
||||
|
||||
int accept(ACCEPT_SIG) {
|
||||
DEBUG_ATTN("fd=%d", fd);
|
||||
if (!check_intercept_enabled())
|
||||
return realaccept(fd, addr, addrlen);
|
||||
|
||||
// Check that this is a valid fd
|
||||
if(fcntl(fd, F_GETFD) < 0) {
|
||||
return -1;
|
||||
errno = EBADF;
|
||||
DEBUG_ERROR("EBADF");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
int opt;
|
||||
socklen_t opt_len;
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) {
|
||||
errno = ENOTSOCK;
|
||||
return -1;
|
||||
}
|
||||
// Check that this socket supports accept()
|
||||
if((opt != SOCK_STREAM) && (opt != SOCK_SEQPACKET)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
// Check that we haven't hit the soft-limit file descriptors allowed
|
||||
struct rlimit rl;
|
||||
getrlimit(RLIMIT_NOFILE, &rl);
|
||||
if(fd >= rl.rlim_cur){
|
||||
errno = EMFILE;
|
||||
DEBUG_ERROR("EMFILE");
|
||||
return -1;
|
||||
}
|
||||
// Check address length
|
||||
if(addrlen < 0) {
|
||||
errno = EINVAL;
|
||||
DEBUG_ERROR("EINVAL");
|
||||
return -1;
|
||||
}
|
||||
// redirect calls for standard I/O descriptors to kernel
|
||||
if(fd == 0 || fd == 1 || fd == 2){
|
||||
DEBUG_BLANK("realaccept(): ");
|
||||
return(realaccept(fd, addr, addrlen));
|
||||
}
|
||||
|
||||
return zts_accept(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------- listen()--------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int backlog
|
||||
|
||||
int listen(LISTEN_SIG)
|
||||
{
|
||||
DEBUG_ATTN("fd=%d", fd);
|
||||
if (!check_intercept_enabled() || !connected_to_service(fd))
|
||||
return reallisten(fd, backlog);
|
||||
// make sure we don't touch any standard outputs
|
||||
if(fd == 0 || fd == 1 || fd == 2)
|
||||
return reallisten(fd, backlog);
|
||||
return zts_listen(fd, backlog);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------- close() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd
|
||||
|
||||
int close(CLOSE_SIG) {
|
||||
DEBUG_EXTRA("fd=%d", fd);
|
||||
if(!check_intercept_enabled())
|
||||
return realclose(fd);
|
||||
return zts_close(fd);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// -------------------------------- getsockname() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
|
||||
int getsockname(GETSOCKNAME_SIG)
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
#if !defined(__IOS__)
|
||||
if (!check_intercept_enabled())
|
||||
return realgetsockname(fd, addr, addrlen);
|
||||
#endif
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
if(!connected_to_service(fd)) {
|
||||
DEBUG_ERROR("fd=%d not used by service", fd);
|
||||
return realgetsockname(fd, addr, addrlen);
|
||||
}
|
||||
return zts_getsockname(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ syscall() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// long number, ...
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#if defined(__linux__)
|
||||
long syscall(SYSCALL_SIG)
|
||||
{
|
||||
va_list ap;
|
||||
uintptr_t a,b,c,d,e,f;
|
||||
va_start(ap, number);
|
||||
a=va_arg(ap, uintptr_t);
|
||||
b=va_arg(ap, uintptr_t);
|
||||
c=va_arg(ap, uintptr_t);
|
||||
d=va_arg(ap, uintptr_t);
|
||||
e=va_arg(ap, uintptr_t);
|
||||
f=va_arg(ap, uintptr_t);
|
||||
va_end(ap);
|
||||
|
||||
if (!check_intercept_enabled())
|
||||
return realsyscall(number,a,b,c,d,e,f);
|
||||
DEBUG_INFO("number=%ld", number);
|
||||
|
||||
#if defined(__i386__)
|
||||
// TODO: Implement for 32-bit systems: syscall(__NR_socketcall, 18, args);
|
||||
// args[0] = (unsigned long) fd;
|
||||
// args[1] = (unsigned long) addr;
|
||||
// args[2] = (unsigned long) addrlen;
|
||||
// args[3] = (unsigned long) flags;
|
||||
#else
|
||||
if(number == __NR_accept4) {
|
||||
int sockfd = a;
|
||||
struct sockaddr * addr = (struct sockaddr*)b;
|
||||
socklen_t * addrlen = (socklen_t*)c;
|
||||
int flags = d;
|
||||
int old_errno = errno;
|
||||
int err = accept4(sockfd, addr, addrlen, flags);
|
||||
errno = old_errno;
|
||||
err = err == -EBADF ? -EAGAIN : err;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
return realsyscall(number,a,b,c,d,e,f);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // _SDK_INTERCEPT_
|
||||
|
||||
458
src/proxy.cpp
458
src/proxy.cpp
@@ -1,458 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "tap.hpp"
|
||||
|
||||
#include "Phy.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
#define SOCKS_OPEN 0
|
||||
#define SOCKS_CONNECT_INIT 1
|
||||
#define SOCKS_CONNECT_IPV4 2
|
||||
#define SOCKS_UDP 3 // ?
|
||||
#define SOCKS_COMPLETE 4
|
||||
|
||||
#define CONNECTION_TIMEOUT 8
|
||||
|
||||
#define IDX_VERSION 0
|
||||
#define IDX_COMMAND 1
|
||||
#define IDX_METHOD 1
|
||||
#define IDX_FRAG 1
|
||||
#define IDX_ERROR_CODE 1
|
||||
#define IDX_NMETHODS 1
|
||||
#define IDX_METHODS 2 // Supported methods
|
||||
#define IDX_ATYP 3
|
||||
#define IDX_DST_ADDR 4 // L:D where L = addrlen, D = addr
|
||||
#define IDX_
|
||||
|
||||
#define THIS_PROXY_VERSION 5
|
||||
#define MAX_ADDR_LEN 32
|
||||
#define PORT_LEN 2
|
||||
|
||||
void dwr(int level, const char *fmt, ... );
|
||||
|
||||
namespace ZeroTier
|
||||
{
|
||||
int NetconEthernetTap::getProxyServerAddress(struct sockaddr_storage *addr) {
|
||||
if(sockstate >= 0) {
|
||||
addr = &proxyServerAddress;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetconEthernetTap::getProxyServerPort() {
|
||||
struct sockaddr_in *in4;
|
||||
in4 = (struct sockaddr_in *)&proxyServerAddress;
|
||||
return in4->sin_port;
|
||||
}
|
||||
|
||||
int NetconEthernetTap::stopProxyServer()
|
||||
{
|
||||
DEBUG_INFO();
|
||||
if(proxyListenPhySocket) {
|
||||
_phy.close(proxyListenPhySocket);
|
||||
return 0;
|
||||
}
|
||||
DEBUG_ERROR("invalid proxyListenPhySocket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetconEthernetTap::startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr)
|
||||
{
|
||||
// Address of proxy server is determined in the following order:
|
||||
// - Provided address in param: addr
|
||||
// - If no address, assume 127.0.0.1:<networks.d/nwid.port>
|
||||
// - If no port assignment file, 127.0.0.1:RANDOM_PORT
|
||||
|
||||
DEBUG_INFO();
|
||||
int portno = -1;
|
||||
if(addr) {
|
||||
DEBUG_INFO("using provided address");
|
||||
// This address pointer may come from a different memory space and might be de-allocated, so we keep a copy
|
||||
memcpy(&proxyServerAddress, addr, sizeof(struct sockaddr_storage));
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
|
||||
proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this);
|
||||
sockstate = SOCKS_OPEN;
|
||||
// DEBUG_INFO("SOCKS5 proxy server address for <%.16llx> is: <%s> (sock=%p)", nwid, inet_ntoa(in4->sin_addr), /*ntohs(in4->sin_port), */(void*)&proxyListenPhySocket);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DEBUG_INFO("no address provided. Checking port file.");
|
||||
// Look for a port file for this network's proxy server instance
|
||||
char portFile[4096];
|
||||
Utils::snprintf(portFile,sizeof(portFile),"%s/networks.d/%.16llx.port",homepath,nwid);
|
||||
std::string portStr;
|
||||
DEBUG_INFO("reading port from: %s\n", portFile);
|
||||
if(ZeroTier::OSUtils::fileExists(portFile,true))
|
||||
{
|
||||
if(ZeroTier::OSUtils::readFile(portFile, portStr)) {
|
||||
portno = atoi(portStr.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int randp = 0;
|
||||
Utils::getSecureRandom(&randp,sizeof(randp));
|
||||
portno = 1000 + (randp % 1000);
|
||||
// DEBUG_INFO("no port specified in networks.d/%.16llx.port, randomly picking port", nwid);
|
||||
std::stringstream ss;
|
||||
ss << portno;
|
||||
portStr = ss.str();
|
||||
if(!ZeroTier::OSUtils::writeFile(portFile, portStr)) {
|
||||
DEBUG_ERROR("unable to write proxy port file: %s", portFile);
|
||||
}
|
||||
}
|
||||
struct sockaddr_in in4;
|
||||
memset(&in4,0,sizeof(in4));
|
||||
in4.sin_family = AF_INET;
|
||||
in4.sin_addr.s_addr = Utils::hton((uint32_t)0x00000000); // right now we just listen for TCP @0.0.0.0
|
||||
in4.sin_port = Utils::hton((uint16_t)portno);
|
||||
proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this);
|
||||
sockstate = SOCKS_OPEN;
|
||||
//DEBUG_INFO("SOCKS5 proxy server address for <%.16llx> is: <%s:%d> (sock=%p)\n", nwid, , portno, (void*)&proxyListenPhySocket);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExtractAddress(int addr_type, unsigned char *buf, struct sockaddr_in * addr)
|
||||
{
|
||||
// TODO: Generalize extraction logic
|
||||
if(addr_type == 144)
|
||||
{
|
||||
// Extract address from buffer
|
||||
int domain_len = buf[IDX_DST_ADDR]; // (L):D
|
||||
char addr_[MAX_ADDR_LEN];
|
||||
int port_ = 0;
|
||||
memset(addr_, 0, MAX_ADDR_LEN);
|
||||
memcpy(addr_, &buf[IDX_DST_ADDR+1], domain_len); // L:(D)
|
||||
memcpy(&port_, &buf[IDX_DST_ADDR+1]+(domain_len), PORT_LEN);
|
||||
port_ = Utils::hton((uint16_t)port_);
|
||||
std::string addr_str(addr_);
|
||||
// Format address for Netcon/lwIP
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = port_;
|
||||
addr->sin_addr.s_addr = inet_addr(addr_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||
{
|
||||
DEBUG_INFO("sock=%p, len=%lu", (void*)&sock, len);
|
||||
unsigned char *buf;
|
||||
buf = (unsigned char *)data;
|
||||
|
||||
// Get connection for this PhySocket
|
||||
Connection *conn = getConnection(sock);
|
||||
if(!conn) {
|
||||
DEBUG_INFO("unable to locate Connection for sock=%p", (void*)&sock);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write data to lwIP PCB (outgoing)
|
||||
if(conn->proxy_conn_state == SOCKS_COMPLETE)
|
||||
{
|
||||
if(len) {
|
||||
DEBUG_INFO("len=%lu\n", len);
|
||||
memcpy((&conn->txbuf)+(conn->txsz), buf, len);
|
||||
conn->txsz += len;
|
||||
handleWrite(conn);
|
||||
}
|
||||
}
|
||||
|
||||
if(conn->proxy_conn_state==SOCKS_UDP)
|
||||
{
|
||||
DEBUG_INFO("SOCKS_UDP from client\n");
|
||||
// +----+------+------+----------+----------+----------+
|
||||
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
|
||||
// +----+------+------+----------+----------+----------+
|
||||
// | 2 | 1 | 1 | Variable | 2 | Variable |
|
||||
// +----+------+------+----------+----------+----------+
|
||||
|
||||
//int fragment_num = buf[2];
|
||||
//int addr_type = buf[3];
|
||||
}
|
||||
|
||||
// SOCKS_OPEN
|
||||
// +----+----------+----------+
|
||||
// |VER | NMETHODS | METHODS |
|
||||
// +----+----------+----------+
|
||||
// | 1 | 1 | 1 to 255 |
|
||||
// +----+----------+----------+
|
||||
if(conn->proxy_conn_state==SOCKS_OPEN)
|
||||
{
|
||||
if(len >= 3)
|
||||
{
|
||||
//int version = buf[IDX_VERSION];
|
||||
//int methodsLength = buf[IDX_NMETHODS];
|
||||
int firstSupportedMethod = buf[IDX_METHODS];
|
||||
int supportedMethod = 0;
|
||||
|
||||
// Password auth
|
||||
if(firstSupportedMethod == 2) {
|
||||
supportedMethod = firstSupportedMethod;
|
||||
}
|
||||
//DEBUG_INFO(" INFO <ver=%d, meth_len=%d, supp_meth=%d>", version, methodsLength, supportedMethod);
|
||||
|
||||
// Send METHOD selection msg
|
||||
// +----+--------+
|
||||
// |VER | METHOD |
|
||||
// +----+--------+
|
||||
// | 1 | 1 |
|
||||
// +----+--------+
|
||||
char reply[2];
|
||||
reply[IDX_VERSION] = THIS_PROXY_VERSION; // version
|
||||
reply[IDX_METHOD] = supportedMethod;
|
||||
_phy.streamSend(sock, reply, sizeof(reply));
|
||||
|
||||
// Set state for next message
|
||||
conn->proxy_conn_state = SOCKS_CONNECT_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
// SOCKS_CONNECT
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
if(conn->proxy_conn_state==SOCKS_CONNECT_INIT)
|
||||
{
|
||||
// Ex. 4(meta) + 4(ipv4) + 2(port) = 10
|
||||
if(len >= 10)
|
||||
{
|
||||
//int version = buf[IDX_VERSION];
|
||||
int cmd = buf[IDX_COMMAND];
|
||||
int addr_type = buf[IDX_ATYP];
|
||||
|
||||
//DEBUG_INFO("SOCKS REQUEST = <ver=%d, cmd=%d, typ=%d>", version, cmd, addr_type);
|
||||
|
||||
// CONNECT request
|
||||
if(cmd == 1) {
|
||||
DEBUG_INFO("CONNECT request");
|
||||
// Ipv4
|
||||
/*
|
||||
if(addr_type == 144)
|
||||
{
|
||||
//DEBUG_INFO("IPv4\n");
|
||||
int raw_addr;
|
||||
memcpy(&raw_addr, &buf[4], 4);
|
||||
char newaddr[16];
|
||||
inet_ntop(AF_INET, &raw_addr, (char*)newaddr, INET_ADDRSTRLEN);
|
||||
DEBUG_INFO("new addr = %s\n", newaddr);
|
||||
|
||||
int rawport, port;
|
||||
memcpy(&rawport, &buf[5], 2);
|
||||
port = Utils::ntoh(rawport);
|
||||
DEBUG_INFO("new port = %d\n", port);
|
||||
|
||||
// Assemble new address
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_addr.s_addr = IPADDR_ANY;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = Utils::hton(8080);
|
||||
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
DEBUG_INFO("fd = %d\n", fd);
|
||||
|
||||
if(fd < 0)
|
||||
perror("socket");
|
||||
|
||||
int err = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
DEBUG_INFO("connect_err = %d\n", err);
|
||||
if(err < 0)
|
||||
perror("connect");
|
||||
}
|
||||
*/
|
||||
// Fully-qualified domain name
|
||||
if(addr_type == 144)
|
||||
{
|
||||
int domain_len = buf[IDX_DST_ADDR]; // (L):D
|
||||
struct sockaddr_in addr;
|
||||
ExtractAddress(addr_type,buf,&addr);
|
||||
PhySocket * new_sock = handleSocketProxy(sock, SOCK_STREAM);
|
||||
if(!new_sock)
|
||||
DEBUG_ERROR("error while creating proxied-socket");
|
||||
handleConnectProxy(sock, &addr);
|
||||
|
||||
// Convert connection err code into SOCKS-err-code
|
||||
// X'00' succeeded
|
||||
// X'01' general SOCKS server failure
|
||||
// X'02' connection not allowed by ruleset
|
||||
// X'03' Network unreachable
|
||||
// X'04' Host unreachable
|
||||
// X'05' Connection refused
|
||||
// X'06' TTL expired
|
||||
// X'07' Command not supported
|
||||
// X'08' Address type not supported
|
||||
// X'09' to X'FF' unassigned
|
||||
|
||||
// SOCKS_CONNECT_REPLY
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
|
||||
DEBUG_INFO("REPLY = %d", addr.sin_port);
|
||||
char reply[len]; // TODO: determine proper length
|
||||
int addr_len = domain_len;
|
||||
memset(reply, 0, len); // Create reply buffer at least as big as incoming SOCKS request data
|
||||
memcpy(&reply[IDX_DST_ADDR],&buf[IDX_DST_ADDR],domain_len);
|
||||
reply[IDX_VERSION] = THIS_PROXY_VERSION; // version
|
||||
reply[IDX_ERROR_CODE] = 0; // success/err code
|
||||
reply[2] = 0; // RSV
|
||||
reply[IDX_ATYP] = addr_type; // ATYP (1, 3, 4)
|
||||
reply[IDX_DST_ADDR] = addr_len;
|
||||
memcpy(&reply[IDX_DST_ADDR+domain_len], &addr.sin_port, PORT_LEN); // PORT
|
||||
_phy.streamSend(sock, reply, sizeof(reply));
|
||||
|
||||
// Any further data activity on this PhySocket will be considered data to send
|
||||
conn->proxy_conn_state = SOCKS_COMPLETE;
|
||||
}
|
||||
// END CONNECT
|
||||
}
|
||||
|
||||
// BIND Request
|
||||
if(cmd == 2)
|
||||
{
|
||||
DEBUG_INFO("BIND request");
|
||||
//char raw_addr[15];
|
||||
//int bind_port;
|
||||
}
|
||||
|
||||
// UDP ASSOCIATION Request
|
||||
if(cmd == 3)
|
||||
{
|
||||
// PORT supplied should be port assigned by server in previous msg
|
||||
DEBUG_INFO("UDP association request");
|
||||
|
||||
// SOCKS_CONNECT (Cont.)
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
|
||||
// NOTE: Similar to cmd==1, should consolidate logic
|
||||
|
||||
// NOTE: Can't separate out port with method used in IPv4 block
|
||||
int domain_len = buf[4];
|
||||
// Grab Addr:Port
|
||||
char raw_addr[domain_len];
|
||||
memset(raw_addr, 0, domain_len);
|
||||
memcpy(raw_addr, &buf[5], domain_len);
|
||||
|
||||
std::string ip, port, addrstr(raw_addr);
|
||||
ssize_t del = addrstr.find(":");
|
||||
ip = addrstr.substr(0, del);
|
||||
port = addrstr.substr(del+1, domain_len);
|
||||
|
||||
// Create new lwIP PCB
|
||||
PhySocket * new_sock = handleSocketProxy(sock, SOCK_DGRAM);
|
||||
|
||||
DEBUG_INFO("sock = %p", (void*)&sock);
|
||||
DEBUG_INFO("new_sock = %p", (void*)&new_sock);
|
||||
if(!new_sock)
|
||||
DEBUG_ERROR("error while creating proxied-socket");
|
||||
|
||||
// Form address
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, '0', sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = Utils::hton((uint16_t)atoi(port.c_str()));
|
||||
addr.sin_addr.s_addr = inet_addr(ip.c_str());
|
||||
//addr.sin_addr.s_addr = inet_addr("10.5.5.2");
|
||||
handleConnectProxy(sock, &addr);
|
||||
conn->proxy_conn_state = SOCKS_UDP;
|
||||
}
|
||||
|
||||
//if(addr_type == 1337)
|
||||
//{
|
||||
// // IPv6
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
|
||||
{
|
||||
DEBUG_INFO("sock=%p", (void*)&sockN);
|
||||
Connection *newConn = new Connection();
|
||||
newConn->sock = sockN;
|
||||
_phy.setNotifyWritable(sockN, false);
|
||||
_Connections.push_back(newConn);
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
|
||||
{
|
||||
DEBUG_INFO("sock=%p", (void*)&sock);
|
||||
}
|
||||
|
||||
// Unused -- no UDP or TCP from this thread/Phy<>
|
||||
void NetconEthernetTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, const struct sockaddr *from,void *data,unsigned long len)
|
||||
{
|
||||
DEBUG_INFO("len = %lu", len);
|
||||
if(len) {
|
||||
Connection *conn = getConnection(sock);
|
||||
if(!conn){
|
||||
DEBUG_ERROR("unable to locate Connection: sock=%p", (void*)sock);
|
||||
return;
|
||||
}
|
||||
unsigned char *buf = (unsigned char*)data;
|
||||
memcpy((&conn->txbuf)+(conn->txsz), buf, len);
|
||||
conn->txsz += len;
|
||||
handleWrite(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnTcpClose(PhySocket *sock,void **uptr)
|
||||
{
|
||||
DEBUG_INFO("sock=%p", (void*)&sock);
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
closeConnection(sock);
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnTcpWritable(PhySocket *sock,void **uptr, bool lwip_invoked)
|
||||
{
|
||||
DEBUG_INFO("sock=%p", (void*)&sock);
|
||||
handleRead(sock,uptr,true);
|
||||
}
|
||||
|
||||
// RX data on stream socks and send back over client sock's underlying fd
|
||||
void NetconEthernetTap::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable)
|
||||
{
|
||||
DEBUG_INFO("sock=%p", (void*&)sock);
|
||||
}
|
||||
}
|
||||
345
src/rpc.c
345
src/rpc.c
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifdef USE_GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "sdk.h"
|
||||
#include "rpc.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// externs common between SDK_Intercept and SDK_Socket from SDK.h
|
||||
int (*realsocket)(SOCKET_SIG);
|
||||
int (*realconnect)(CONNECT_SIG);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SERVICE_CONNECT_ATTEMPTS 30
|
||||
|
||||
ssize_t sock_fd_write(int sock, int fd);
|
||||
ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
|
||||
|
||||
static int rpc_count;
|
||||
|
||||
static pthread_mutex_t lock;
|
||||
void rpc_mutex_init() {
|
||||
if(pthread_mutex_init(&lock, NULL) != 0) {
|
||||
}
|
||||
}
|
||||
void rpc_mutex_destroy() {
|
||||
pthread_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a new file descriptor from the service
|
||||
*/
|
||||
int get_new_fd(int sock)
|
||||
{
|
||||
char buf[BUF_SZ];
|
||||
int newfd;
|
||||
ssize_t size = sock_fd_read(sock, buf, sizeof(buf), &newfd);
|
||||
if(size > 0)
|
||||
return newfd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a return value from the service and sets errno (if applicable)
|
||||
*/
|
||||
int get_retval(int rpc_sock)
|
||||
{
|
||||
if(rpc_sock >= 0) {
|
||||
int retval;
|
||||
int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
|
||||
char retbuf[BUF_SZ];
|
||||
memset(&retbuf, 0, sz);
|
||||
long n_read = read(rpc_sock, &retbuf, sz);
|
||||
if(n_read > 0) {
|
||||
memcpy(&retval, &retbuf[1], sizeof(retval));
|
||||
memcpy(&errno, &retbuf[1+sizeof(retval)], sizeof(errno));
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int load_symbols_rpc()
|
||||
{
|
||||
#if defined(__IOS__) || defined(__UNITY_3D__)
|
||||
realsocket = dlsym(RTLD_NEXT, "socket");
|
||||
realconnect = dlsym(RTLD_NOW, "connect");
|
||||
if(!realconnect || !realsocket)
|
||||
return -1;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rpc_join(char * sockname)
|
||||
{
|
||||
if(sockname == NULL) {
|
||||
DEBUG_ERROR("warning, rpc netpath is NULL");
|
||||
}
|
||||
if(!load_symbols_rpc())
|
||||
return -1;
|
||||
struct sockaddr_un addr;
|
||||
int conn_err = -1, attempts = 0;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)-1);
|
||||
int sock;
|
||||
|
||||
#if defined(SDK_INTERCEPT)
|
||||
if((sock = realsocket(AF_UNIX, SOCK_STREAM, 0)) < 0){
|
||||
#else
|
||||
if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
|
||||
#endif
|
||||
DEBUG_ERROR("error creating RPC socket");
|
||||
return -1;
|
||||
}
|
||||
while((conn_err != 0) /* && (attempts < SERVICE_CONNECT_ATTEMPTS) */){
|
||||
#if defined(SDK_INTERCEPT)
|
||||
if((conn_err = realconnect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) {
|
||||
#else
|
||||
if((conn_err = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) {
|
||||
#endif
|
||||
DEBUG_ERROR("error connecting to RPC socket (%s). Re-attempting...", sockname);
|
||||
usleep(100000);
|
||||
}
|
||||
else
|
||||
return sock;
|
||||
attempts++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to the service
|
||||
*/
|
||||
int rpc_send_command(char *path, int cmd, int forfd, void *data, int len)
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
char c, padding[] = {PADDING};
|
||||
char cmdbuf[BUF_SZ], CANARY[CANARY_SZ+PADDING_SZ], metabuf[BUF_SZ];
|
||||
|
||||
memcpy(CANARY+CANARY_SZ, padding, sizeof(padding));
|
||||
uint64_t canary_num;
|
||||
// ephemeral RPC socket used only for this command
|
||||
int rpc_sock = rpc_join(path);
|
||||
|
||||
// Generate token
|
||||
int fdrand = open("/dev/urandom", O_RDONLY);
|
||||
if(read(fdrand, &CANARY, CANARY_SZ) < 0) {
|
||||
DEBUG_ERROR("unable to read from /dev/urandom for RPC canary data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fdrand);
|
||||
memcpy(&canary_num, CANARY, CANARY_SZ);
|
||||
cmdbuf[CMD_ID_IDX] = cmd;
|
||||
memcpy(&cmdbuf[CANARY_IDX], &canary_num, CANARY_SZ);
|
||||
memcpy(&cmdbuf[STRUCT_IDX], data, len);
|
||||
|
||||
rpc_count++;
|
||||
memset(metabuf, 0, BUF_SZ);
|
||||
#if defined(__linux__)
|
||||
#if !defined(__ANDROID__)
|
||||
pid_t pid = 5; //syscall(SYS_getpid);
|
||||
pid_t tid = 4;//syscall(SYS_gettid);
|
||||
#else
|
||||
// Dummy values
|
||||
pid_t pid = 5;
|
||||
pid_t tid = gettid();
|
||||
#endif
|
||||
#endif
|
||||
char timestring[20];
|
||||
time_t timestamp;
|
||||
timestamp = time(NULL);
|
||||
strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(×tamp));
|
||||
#if defined(__linux__)
|
||||
memcpy(&metabuf[IDX_PID], &pid, sizeof(pid_t) ); /* pid */
|
||||
memcpy(&metabuf[IDX_TID], &tid, sizeof(pid_t) ); /* tid */
|
||||
#endif
|
||||
memcpy(&metabuf[IDX_TIME], ×tring, 20 ); /* timestamp */
|
||||
|
||||
/* Combine command flag+payload with RPC metadata */
|
||||
memcpy(metabuf, RPC_PHRASE, RPC_PHRASE_SZ); // Write signal phrase
|
||||
memcpy(&metabuf[IDX_PAYLOAD], cmdbuf, len + 1 + CANARY_SZ);
|
||||
|
||||
// Write RPC
|
||||
long n_write = write(rpc_sock, &metabuf, BUF_SZ);
|
||||
if(n_write < 0) {
|
||||
DEBUG_ERROR("error writing command to service (CMD = %d)", cmdbuf[CMD_ID_IDX]);
|
||||
errno = 0;
|
||||
}
|
||||
// Write token to corresponding data stream
|
||||
if(read(rpc_sock, &c, 1) < 0) {
|
||||
DEBUG_ERROR("unable to read RPC ACK byte from service.");
|
||||
close(rpc_sock);
|
||||
return -1;
|
||||
}
|
||||
if(c == 'z' && n_write > 0 && forfd > -1){
|
||||
if(send(forfd, &CANARY, CANARY_SZ+PADDING_SZ, 0) < 0) {
|
||||
perror("send: \n");
|
||||
DEBUG_ERROR("unable to write canary to stream (fd=%d)", forfd);
|
||||
close(rpc_sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Process response from service
|
||||
int ret = ERR_OK;
|
||||
if(n_write > 0) {
|
||||
if(cmdbuf[CMD_ID_IDX]==RPC_SOCKET) {
|
||||
pthread_mutex_unlock(&lock);
|
||||
return rpc_sock; // Used as new socket
|
||||
}
|
||||
if(cmdbuf[CMD_ID_IDX]==RPC_CONNECT
|
||||
|| cmdbuf[CMD_ID_IDX]==RPC_BIND
|
||||
|| cmdbuf[CMD_ID_IDX]==RPC_LISTEN) {
|
||||
ret = get_retval(rpc_sock);
|
||||
}
|
||||
if(cmdbuf[CMD_ID_IDX]==RPC_GETSOCKNAME || cmdbuf[CMD_ID_IDX]==RPC_GETPEERNAME) {
|
||||
pthread_mutex_unlock(&lock);
|
||||
return rpc_sock; // Don't close rpc here, we'll use it to read getsockopt_st
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
close(rpc_sock); // We're done with this RPC socket, close it (if type-R)
|
||||
pthread_mutex_unlock(&lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send file descriptor
|
||||
*/
|
||||
ssize_t sock_fd_write(int sock, int fd)
|
||||
{
|
||||
ssize_t size;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char buf = '\0';
|
||||
int buflen = 1;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
char control[CMSG_SPACE(sizeof (int))];
|
||||
} cmsgu;
|
||||
struct cmsghdr *cmsg;
|
||||
iov.iov_base = &buf;
|
||||
iov.iov_len = buflen;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
if (fd != -1) {
|
||||
msg.msg_control = cmsgu.control;
|
||||
msg.msg_controllen = sizeof(cmsgu.control);
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof (int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
*((int *) CMSG_DATA(cmsg)) = fd;
|
||||
} else {
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
}
|
||||
size = sendmsg(sock, &msg, 0);
|
||||
if (size < 0)
|
||||
perror ("sendmsg");
|
||||
return size;
|
||||
}
|
||||
/*
|
||||
* Read a file descriptor
|
||||
*/
|
||||
ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
|
||||
{
|
||||
ssize_t size;
|
||||
if (fd) {
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
char control[CMSG_SPACE(sizeof (int))];
|
||||
} cmsgu;
|
||||
|
||||
struct cmsghdr *cmsg;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = bufsize;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgu.control;
|
||||
msg.msg_controllen = sizeof(cmsgu.control);
|
||||
size = recvmsg (sock, &msg, 0);
|
||||
|
||||
if (size < 0)
|
||||
return -1;
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
|
||||
if (cmsg->cmsg_level != SOL_SOCKET) {
|
||||
DEBUG_ERROR("invalid cmsg_level %d",cmsg->cmsg_level);
|
||||
return -1;
|
||||
}
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
DEBUG_ERROR("invalid cmsg_type %d",cmsg->cmsg_type);
|
||||
return -1;
|
||||
}
|
||||
*fd = *((int *) CMSG_DATA(cmsg));
|
||||
} else {
|
||||
*fd = -1;}
|
||||
} else {
|
||||
size = read (sock, buf, bufsize);
|
||||
if (size < 0) {
|
||||
DEBUG_ERROR("sock_fd_read(): read: Error");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
144
src/rpc.h
144
src/rpc.h
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef __RPCLIB_H_
|
||||
#define __RPCLIB_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define CANARY_SZ sizeof(uint64_t)
|
||||
#define PADDING_SZ 12
|
||||
#define PADDING 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
|
||||
|
||||
#define RPC_PHRASE "zerotier\0"
|
||||
#define RPC_PHRASE_SZ 9
|
||||
#define RPC_TIMESTAMP_SZ 20
|
||||
// 1st RPC section (metdata)
|
||||
#define IDX_SIGNAL_PHRASE 0
|
||||
#define IDX_PID IDX_SIGNAL_PHRASE + RPC_PHRASE_SZ
|
||||
#define IDX_TID sizeof(pid_t) + IDX_PID
|
||||
#define IDX_TIME IDX_TID + sizeof(int)
|
||||
#define IDX_PAYLOAD IDX_TIME + RPC_TIMESTAMP_SZ
|
||||
// 2nd RPC section (payload and canary)
|
||||
#define CMD_ID_IDX 0
|
||||
#define CANARY_IDX 1
|
||||
#define STRUCT_IDX CANARY_IDX+CANARY_SZ
|
||||
|
||||
#define BUF_SZ 512
|
||||
|
||||
#define ERR_OK 0
|
||||
|
||||
/* RPC codes */
|
||||
#define RPC_UNDEFINED 0
|
||||
#define RPC_CONNECT 1
|
||||
#define RPC_CONNECT_SOCKARG 2
|
||||
#define RPC_CLOSE 3
|
||||
#define RPC_READ 4
|
||||
#define RPC_WRITE 5
|
||||
#define RPC_BIND 6
|
||||
#define RPC_ACCEPT 7
|
||||
#define RPC_LISTEN 8
|
||||
#define RPC_SOCKET 9
|
||||
#define RPC_SHUTDOWN 10
|
||||
#define RPC_GETSOCKNAME 11
|
||||
#define RPC_GETPEERNAME 12
|
||||
#define RPC_RETVAL 13
|
||||
#define RPC_IS_CONNECTED 14
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int get_retval(int);
|
||||
int rpc_join( char * sockname);
|
||||
int rpc_send_command(char *path, int cmd, int forfd, void *data, int len);
|
||||
|
||||
int get_new_fd(int sock);
|
||||
ssize_t sock_fd_write(int sock, int fd);
|
||||
ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
|
||||
|
||||
void rpc_mutex_destroy();
|
||||
void rpc_mutex_init();
|
||||
|
||||
|
||||
/* Structures used for sending commands via RPC mechanism */
|
||||
|
||||
struct bind_st {
|
||||
int fd;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int tid;
|
||||
};
|
||||
|
||||
struct connect_st {
|
||||
int fd;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int tid;
|
||||
};
|
||||
|
||||
struct close_st {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct listen_st {
|
||||
int fd;
|
||||
int backlog;
|
||||
int tid;
|
||||
};
|
||||
|
||||
struct socket_st {
|
||||
int socket_family;
|
||||
int socket_type;
|
||||
int protocol;
|
||||
int tid;
|
||||
};
|
||||
|
||||
struct accept_st {
|
||||
int fd;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int tid;
|
||||
};
|
||||
|
||||
struct shutdown_st {
|
||||
int socket;
|
||||
int how;
|
||||
};
|
||||
|
||||
struct getsockname_st {
|
||||
int fd;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
255
src/sdk.h
255
src/sdk.h
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef _ZT_SDK_H
|
||||
#define _ZT_SDK_H 1
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------- Compilation flag checks -------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#define INTERCEPT_ENABLED 111
|
||||
#define INTERCEPT_DISABLED 222
|
||||
#define MAX_DIR_SZ 256 // Max path length used for home dir
|
||||
|
||||
#if defined(SDK_SERVICE)
|
||||
// Sanity checks for compilation
|
||||
#if !defined(SDK_LWIP) && !defined(SDK_PICOTCP)
|
||||
#error "No network stack specified, use SDK_LWIP=1, SDK_PICOTCP=1, or similar"
|
||||
#endif
|
||||
#if defined(SDK_LWIP) && defined(SDK_PICOTCP)
|
||||
#error "Dual stacks is not currently supported, try one or the other"
|
||||
#endif
|
||||
#if !defined(SDK_IPV4) && !defined(SDK_IPV6)
|
||||
#error "No IP protocol version specified, use SDK_IPV4=1, or SDK_IPV6=1"
|
||||
#endif
|
||||
#if !defined(SDK_IPV4) && !defined(SDK_IPV6)
|
||||
#error "Dual protocol versions is not currently supported. try one or the other"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// -------------- Socket API function signatures for convenience ----------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#define SETSOCKOPT_SIG int fd, int level, int optname, const void *optval, socklen_t optlen
|
||||
#define GETSOCKOPT_SIG int fd, int level, int optname, void *optval, socklen_t *optlen
|
||||
#define SENDMSG_SIG int fd, const struct msghdr *msg, int flags
|
||||
#define SENDTO_SIG int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen
|
||||
#define RECV_SIG int fd, void *buf, size_t len, int flags
|
||||
#define RECVFROM_SIG int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen
|
||||
#define RECVMSG_SIG int fd, struct msghdr *msg,int flags
|
||||
#define SEND_SIG int fd, const void *buf, size_t len, int flags
|
||||
#define WRITE_SIG int fd, const void *buf, size_t len
|
||||
#define READ_SIG int fd, void *buf, size_t len
|
||||
#define SOCKET_SIG int socket_family, int socket_type, int protocol
|
||||
#define CONNECT_SIG int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
#define BIND_SIG int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
#define LISTEN_SIG int fd, int backlog
|
||||
#define ACCEPT4_SIG int fd, struct sockaddr *addr, socklen_t *addrlen, int flags
|
||||
#define ACCEPT_SIG int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
#define CLOSE_SIG int fd
|
||||
#define GETSOCKNAME_SIG int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
#define GETPEERNAME_SIG int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
#define FCNTL_SIG int fd, int cmd, int flags
|
||||
#define SYSCALL_SIG long number, ...
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void load_symbols();
|
||||
extern void zts_init_rpc(const char *path, const char *nwid);
|
||||
extern char *api_netpath;
|
||||
extern char *debug_logfile;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------- Ancient INTERCEPT-related cruft --------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// Function pointers to original system calls
|
||||
// - These are used when we detect that either the intercept is not
|
||||
// available or that ZeroTier hasn't administered the given socket
|
||||
#if defined(__linux__)
|
||||
extern int (*realaccept4)(ACCEPT4_SIG);
|
||||
#if !defined(__ANDROID__)
|
||||
extern int (*realsyscall)(SYSCALL_SIG);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
bool check_intercept_enabled();
|
||||
extern int (*realbind)(BIND_SIG);
|
||||
extern int (*realsendmsg)(SENDMSG_SIG);
|
||||
extern ssize_t (*realsendto)(SENDTO_SIG);
|
||||
extern int (*realrecvmsg)(RECVMSG_SIG);
|
||||
extern int (*realrecvfrom)(RECVFROM_SIG);
|
||||
#endif
|
||||
extern int (*realconnect)(CONNECT_SIG);
|
||||
extern int (*realaccept)(ACCEPT_SIG);
|
||||
extern int (*reallisten)(LISTEN_SIG);
|
||||
extern int (*realsocket)(SOCKET_SIG);
|
||||
extern int (*realsetsockopt)(SETSOCKOPT_SIG);
|
||||
extern int (*realgetsockopt)(GETSOCKOPT_SIG);
|
||||
extern int (*realclose)(CLOSE_SIG);
|
||||
extern int (*realgetsockname)(GETSOCKNAME_SIG);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------- Direct API call section -------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// SOCKS5 Proxy Controls
|
||||
int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr);
|
||||
int zts_stop_proxy_server(const char *nwid);
|
||||
int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage *addr);
|
||||
bool zts_proxy_is_running(const char *nwid);
|
||||
// ZT Service Controls
|
||||
void zts_start_service(const char *path);
|
||||
void *zts_start_core_service(void *thread_id);
|
||||
void zts_stop_service();
|
||||
void zts_stop();
|
||||
bool zts_service_is_running();
|
||||
void zts_join_network(const char * nwid);
|
||||
void zts_join_network_soft(const char * filepath, const char * nwid);
|
||||
void zts_leave_network_soft(const char * filepath, const char * nwid);
|
||||
void zts_leave_network(const char * nwid);
|
||||
void zts_get_ipv4_address(const char *nwid, char *addrstr);
|
||||
void zts_get_ipv6_address(const char *nwid, char *addrstr);
|
||||
bool zts_has_address(const char *nwid);
|
||||
int zts_get_device_id(char *devID);
|
||||
int zts_get_device_id_from_file(const char *filepath, char *devID);
|
||||
int zts_get_peer_address(char *peer, const char *devID);
|
||||
unsigned long zts_get_peer_count();
|
||||
//int zts_get_peer_list();
|
||||
char *zts_get_homepath();
|
||||
void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID);
|
||||
void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID);
|
||||
// BSD-like socket API
|
||||
int zts_socket(SOCKET_SIG);
|
||||
int zts_connect(CONNECT_SIG);
|
||||
int zts_bind(BIND_SIG);
|
||||
#if defined(__linux__)
|
||||
int zts_accept4(ACCEPT4_SIG);
|
||||
#endif
|
||||
int zts_accept(ACCEPT_SIG);
|
||||
int zts_listen(LISTEN_SIG);
|
||||
int zts_setsockopt(SETSOCKOPT_SIG);
|
||||
int zts_getsockopt(GETSOCKOPT_SIG);
|
||||
int zts_getsockname(GETSOCKNAME_SIG);
|
||||
int zts_getpeername(GETPEERNAME_SIG);
|
||||
int zts_close(CLOSE_SIG);
|
||||
int zts_fcntl(FCNTL_SIG);
|
||||
ssize_t zts_sendto(SENDTO_SIG);
|
||||
ssize_t zts_sendmsg(SENDMSG_SIG);
|
||||
ssize_t zts_recvfrom(RECVFROM_SIG);
|
||||
ssize_t zts_recvmsg(RECVMSG_SIG);
|
||||
#if defined(__UNITY_3D__)
|
||||
ssize_t zts_recv(int fd, void *buf, int len);
|
||||
ssize_t zts_send(int fd, void *buf, int len);
|
||||
int zts_set_nonblock(int fd); // TODO combine with fcntl()
|
||||
#endif
|
||||
|
||||
#if !defined(__IOS__)
|
||||
void zt_start_service(const char * path, const char *nwid);
|
||||
void zt_join_network(const char * nwid);
|
||||
void zt_leave_network(const char * nwid);
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------- Direct API call section (for Android) ------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME
|
||||
#if defined(__ANDROID__)
|
||||
// ZT SERVICE CONTROLS
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path);
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1stop_service();
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1service_1is_1running(JNIEnv *env, jobject thisObj);
|
||||
JNIEXPORT jstring JNICALL Java_ZeroTier_ZTSDK_zt_1get_1homepath(JNIEnv *env, jobject thisObj);
|
||||
JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1join_1network(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv4_1address(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv6_1address(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1is_1relayed();
|
||||
// SOCKS5 PROXY SERVER CONTROLS
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid, jobject zaddr);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1get_1proxy_1server_1address(JNIEnv *env, jobject thisObj, jstring nwid, jobject zaddr);
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1proxy_1is_1running(JNIEnv *env, jobject thisObj, jstring nwid);
|
||||
// SOCKET API
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept4(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port, jint flags);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog);
|
||||
// TCP
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags);
|
||||
// UDP
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1sendto(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1recvfrom(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr);
|
||||
// GENERAL UTILITY
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1close(JNIEnv *env, jobject thisObj, jint fd);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1fcntl(JNIEnv *env, jobject thisObj, jint socket, jint cmd, jint flags);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1setsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr);
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr);
|
||||
#endif
|
||||
|
||||
|
||||
// Prototypes for redefinition of syscalls
|
||||
// - Implemented in intercept.c
|
||||
#if defined(SDK_INTERCEPT)
|
||||
int socket(SOCKET_SIG);
|
||||
int connect(CONNECT_SIG);
|
||||
int bind(BIND_SIG);
|
||||
#if defined(__linux__)
|
||||
int accept4(ACCEPT4_SIG);
|
||||
#endif
|
||||
int accept(ACCEPT_SIG);
|
||||
int listen(LISTEN_SIG);
|
||||
int setsockopt(SETSOCKOPT_SIG);
|
||||
int getsockopt(GETSOCKOPT_SIG);
|
||||
int getsockname(GETSOCKNAME_SIG);
|
||||
int close(CLOSE_SIG);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _ZT_SDK_H
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef _SDK_UTILS_HPP_
|
||||
#define _SDK_UTILS_HPP_
|
||||
|
||||
#if defined(SDK_LWIP) && defined(SDK_IPV6)
|
||||
#define IP6_ADDR2(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = ZeroTier::Utils::hton((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
|
||||
(ipaddr)->addr[1] = ZeroTier::Utils::hton(((c & 0xffff) << 16) | (d & 0xffff)); \
|
||||
(ipaddr)->addr[2] = ZeroTier::Utils::hton(((e & 0xffff) << 16) | (f & 0xffff)); \
|
||||
(ipaddr)->addr[3] = ZeroTier::Utils::hton(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
|
||||
|
||||
// Convert from standard IPV6 address structure to an lwIP native structure
|
||||
inline void in6_to_ip6(ip6_addr_t *ba, struct sockaddr_in6 *in6)
|
||||
{
|
||||
uint8_t *ip = &(in6->sin6_addr).s6_addr[0];
|
||||
IP6_ADDR2(ba,
|
||||
(((ip[ 0] & 0xffff) << 8) | ((ip[ 1]) & 0xffff)),
|
||||
(((ip[ 2] & 0xffff) << 8) | ((ip[ 3]) & 0xffff)),
|
||||
(((ip[ 4] & 0xffff) << 8) | ((ip[ 5]) & 0xffff)),
|
||||
(((ip[ 6] & 0xffff) << 8) | ((ip[ 7]) & 0xffff)),
|
||||
(((ip[ 8] & 0xffff) << 8) | ((ip[ 9]) & 0xffff)),
|
||||
(((ip[10] & 0xffff) << 8) | ((ip[11]) & 0xffff)),
|
||||
(((ip[12] & 0xffff) << 8) | ((ip[13]) & 0xffff)),
|
||||
(((ip[14] & 0xffff) << 8) | ((ip[15]) & 0xffff))
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SDK_LWIP) && defined(SDK_IPV4)
|
||||
#define ip4_addr1b(ipaddr) (((u8_t*)(ipaddr))[0])
|
||||
#define ip4_addr2b(ipaddr) (((u8_t*)(ipaddr))[1])
|
||||
#define ip4_addr3b(ipaddr) (((u8_t*)(ipaddr))[2])
|
||||
#define ip4_addr4b(ipaddr) (((u8_t*)(ipaddr))[3])
|
||||
|
||||
inline ip_addr_t convert_ip(struct sockaddr_in * addr)
|
||||
{
|
||||
ip_addr_t conn_addr;
|
||||
struct sockaddr_in *ipv4 = addr;
|
||||
short a = ip4_addr1b(&(ipv4->sin_addr));
|
||||
short b = ip4_addr2b(&(ipv4->sin_addr));
|
||||
short c = ip4_addr3b(&(ipv4->sin_addr));
|
||||
short d = ip4_addr4b(&(ipv4->sin_addr));
|
||||
IP4_ADDR(&conn_addr, a,b,c,d);
|
||||
return conn_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _SDK_UTILS_HPP_
|
||||
611
src/service.cpp
611
src/service.cpp
@@ -1,611 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "OneService.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "ZeroTierOne.h"
|
||||
|
||||
#include "tap.hpp"
|
||||
#include "sdk.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static ZeroTier::OneService *zt1Service;
|
||||
|
||||
std::string service_path;
|
||||
std::string localHomeDir; // Local shortened path
|
||||
std::string givenHomeDir; // What the user/application provides as a suggestion
|
||||
std::string homeDir; // The resultant platform-specific dir we *must* use internally
|
||||
std::string netDir; // Where network .conf files are to be written
|
||||
|
||||
pthread_t intercept_thread;
|
||||
pthread_key_t thr_id_key;
|
||||
|
||||
int * intercept_thread_id;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------------- Base zts_* API -----------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// Prototypes
|
||||
void *zts_start_core_service(void *thread_id);
|
||||
void zts_init_rpc(const char * path, const char * nwid);
|
||||
|
||||
//
|
||||
int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr) {
|
||||
DEBUG_INFO();
|
||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||
ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int);
|
||||
if(tap) {
|
||||
if(tap->startProxyServer(homepath, nwid_int, addr) < 0) {
|
||||
DEBUG_ERROR("zts_start_proxy_server(%s): Problem while starting server.", nwid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DEBUG_ERROR("zts_start_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid);
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
int zts_stop_proxy_server(const char *nwid) {
|
||||
DEBUG_INFO();
|
||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||
ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int);
|
||||
if(tap) {
|
||||
if(tap->stopProxyServer() < 0) {
|
||||
DEBUG_ERROR("zts_stop_proxy_server(%s): Problem while stopping server.", nwid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DEBUG_ERROR("zts_stop_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid);
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
bool zts_proxy_is_running(const char *nwid)
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
//
|
||||
int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * addr) {
|
||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||
ZeroTier::NetconEthernetTap * tap = zt1Service->getTap(nwid_int);
|
||||
if(tap) {
|
||||
tap->getProxyServerAddress(addr);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Basic ZT service controls
|
||||
// Will also spin up a SOCKS5 proxy server if USE_SOCKS_PROXY is set
|
||||
void zts_join_network(const char * nwid) {
|
||||
DEBUG_ERROR();
|
||||
std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf";
|
||||
if(!ZeroTier::OSUtils::mkdir(netDir)) {
|
||||
DEBUG_ERROR("unable to create: %s", netDir.c_str());
|
||||
}
|
||||
if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) {
|
||||
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
|
||||
}
|
||||
zt1Service->join(nwid);
|
||||
// Provide the API with the RPC information
|
||||
zts_init_rpc(homeDir.c_str(), nwid);
|
||||
// SOCKS5 Proxy server
|
||||
// Default is 127.0.0.1:RANDOM_PORT
|
||||
#if defined(USE_SOCKS_PROXY)
|
||||
zts_start_proxy_server(homeDir.c_str(), nwid, NULL); // NULL addr for default
|
||||
#endif
|
||||
}
|
||||
// Just create the dir and conf file required, don't instruct the core to do anything
|
||||
void zts_join_network_soft(const char * filepath, const char * nwid) {
|
||||
std::string net_dir = std::string(filepath) + "/networks.d/";
|
||||
std::string confFile = net_dir + std::string(nwid) + ".conf";
|
||||
if(!ZeroTier::OSUtils::mkdir(net_dir)) {
|
||||
DEBUG_ERROR("unable to create: %s", net_dir.c_str());
|
||||
}
|
||||
if(!ZeroTier::OSUtils::fileExists(confFile.c_str(),false)) {
|
||||
if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) {
|
||||
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prevent service from joining network upon startup
|
||||
void zts_leave_network_soft(const char * filepath, const char * nwid) {
|
||||
std::string net_dir = std::string(filepath) + "/networks.d/";
|
||||
ZeroTier::OSUtils::rm((net_dir + nwid + ".conf").c_str());
|
||||
}
|
||||
// Instruct the service to leave the network
|
||||
void zts_leave_network(const char * nwid) {
|
||||
if(zt1Service)
|
||||
zt1Service->leave(nwid);
|
||||
}
|
||||
// Check whether the service is running
|
||||
bool zts_service_is_running() {
|
||||
return !zt1Service ? false : zt1Service->isRunning();
|
||||
}
|
||||
// Stop the service
|
||||
void zts_stop_service() {
|
||||
if(zt1Service)
|
||||
zt1Service->terminate();
|
||||
}
|
||||
// Stop the service, proxy server, stack, etc
|
||||
void zts_stop() {
|
||||
DEBUG_INFO("Stopping STSDK");
|
||||
zts_stop_service();
|
||||
/* TODO: kill each proxy server as well
|
||||
zts_stop_proxy_server(...); */
|
||||
}
|
||||
|
||||
// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations
|
||||
// Now only returns first assigned address per network. Shouldn't normally be a problem.
|
||||
|
||||
// Get IPV4 Address for this device on given network
|
||||
bool zts_has_address(const char *nwid)
|
||||
{
|
||||
char ipv4_addr[64], ipv6_addr[64];
|
||||
memset(ipv4_addr, 0, 64);
|
||||
memset(ipv6_addr, 0, 64);
|
||||
zts_get_ipv4_address(nwid, ipv4_addr);
|
||||
zts_get_ipv6_address(nwid, ipv6_addr);
|
||||
if(!strcmp(ipv4_addr, "-1.-1.-1.-1/-1") && !strcmp(ipv4_addr, "-1.-1.-1.-1/-1")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void zts_get_ipv4_address(const char *nwid, char *addrstr)
|
||||
{
|
||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||
ZeroTier::NetconEthernetTap *tap = zt1Service->getTap(nwid_int);
|
||||
if(tap && tap->_ips.size()){
|
||||
for(int i=0; i<tap->_ips.size(); i++) {
|
||||
if(tap->_ips[i].isV4()) {
|
||||
std::string addr = tap->_ips[i].toString();
|
||||
// DEBUG_EXTRA("addr=%s, addrlen=%d", addr.c_str(), addr.length());
|
||||
memcpy(addrstr, addr.c_str(), addr.length()); // first address found that matches protocol version 4
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy(addrstr, "-1.-1.-1.-1/-1", 14);
|
||||
}
|
||||
}
|
||||
// Get IPV6 Address for this device on given network
|
||||
void zts_get_ipv6_address(const char *nwid, char *addrstr)
|
||||
{
|
||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||
ZeroTier::NetconEthernetTap *tap = zt1Service->getTap(nwid_int);
|
||||
if(tap && tap->_ips.size()){
|
||||
for(int i=0; i<tap->_ips.size(); i++) {
|
||||
if(tap->_ips[i].isV6()) {
|
||||
std::string addr = tap->_ips[i].toString();
|
||||
// DEBUG_EXTRA("addr=%s, addrlen=%d", addr.c_str(), addr.length());
|
||||
memcpy(addrstr, addr.c_str(), addr.length()); // first address found that matches protocol version 4
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy(addrstr, "-1.-1.-1.-1/-1", 14);
|
||||
}
|
||||
}
|
||||
// Get device ID (from running service)
|
||||
int zts_get_device_id(char *devID) {
|
||||
if(zt1Service) {
|
||||
char id[10];
|
||||
sprintf(id, "%lx",zt1Service->getNode()->address());
|
||||
memcpy(devID, id, 10);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
// Get device ID (from file)
|
||||
int zts_get_device_id_from_file(const char *filepath, char *devID) {
|
||||
std::string fname("identity.public");
|
||||
std::string fpath(filepath);
|
||||
|
||||
if(ZeroTier::OSUtils::fileExists((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),false)) {
|
||||
std::string oldid;
|
||||
ZeroTier::OSUtils::readFile((fpath + ZT_PATH_SEPARATOR_S + fname).c_str(),oldid);
|
||||
memcpy(devID, oldid.c_str(), 10); // first 10 bytes of file
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// Get the IP address of a peer if a direct path is available
|
||||
int zts_get_peer_address(char *peer, const char *devID) {
|
||||
if(zt1Service) {
|
||||
ZT_PeerList *pl = zt1Service->getNode()->peers();
|
||||
// uint64_t addr;
|
||||
for(int i=0; i<pl->peerCount; i++) {
|
||||
// ZT_Peer *p = &(pl->peers[i]);
|
||||
// DEBUG_INFO("peer[%d] = %lx", i, p->address);
|
||||
}
|
||||
return pl->peerCount;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
// Return the number of peers on this network
|
||||
unsigned long zts_get_peer_count() {
|
||||
if(zt1Service)
|
||||
return zt1Service->getNode()->peers()->peerCount;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// Return the home path for this instance of ZeroTier
|
||||
char *zts_get_homepath() {
|
||||
return (char*)givenHomeDir.c_str();
|
||||
}
|
||||
// Returns a 6PLANE IPv6 address given a network ID and zerotier ID
|
||||
void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID)
|
||||
{
|
||||
ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv66plane(ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID));
|
||||
memcpy(addr, _6planeAddr.toIpString().c_str(), 40);
|
||||
}
|
||||
// Returns a RFC 4193 IPv6 address given a network ID and zerotier ID
|
||||
void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID)
|
||||
{
|
||||
ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv6rfc4193(ZeroTier::Utils::hexStrToU64(nwid),ZeroTier::Utils::hexStrToU64(devID));
|
||||
memcpy(addr, _6planeAddr.toIpString().c_str(), 40);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------- .NET Interop functions -------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if defined(__UNITY_3D__)
|
||||
// .NET Interop-friendly debug mechanism
|
||||
typedef void (*FuncPtr)( const char * );
|
||||
FuncPtr Debug;
|
||||
void SetDebugFunction( FuncPtr fp ) { Debug = fp; }
|
||||
|
||||
/*
|
||||
// Starts a ZeroTier service at the given path
|
||||
void unity_start_service(char * path, int len) {
|
||||
zts_start_service(path);
|
||||
|
||||
//std::string dstr = std::string(path);
|
||||
//dstr = "unity_start_service(): path = " + dstr;
|
||||
//Debug(dstr.c_str());
|
||||
//init_service(INTERCEPT_DISABLED, path);
|
||||
}
|
||||
// Starts a ZeroTier service and RPC
|
||||
void unity_start_service_and_rpc(char * path, char *nwid, int len) {
|
||||
std::string dstr = std::string(path);
|
||||
dstr = "unity_start_service_and_rpc(): path = " + dstr;
|
||||
Debug(dstr.c_str());
|
||||
init_service_and_rpc(INTERCEPT_DISABLED, path, nwid);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- Other ------------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// For use when symbols are used in Swift
|
||||
|
||||
|
||||
void zts_start_service(const char *path)
|
||||
{
|
||||
DEBUG_INFO("path=%s", path);
|
||||
if(path)
|
||||
homeDir = path;
|
||||
zts_start_core_service(NULL);
|
||||
}
|
||||
|
||||
// Typically used on iOS/OSX
|
||||
#if !defined(__ANDROID__)
|
||||
/*
|
||||
// Starts a service thread and performs basic setup tasks
|
||||
void init_service(int key, const char * path) {
|
||||
givenHomeDir = path;
|
||||
pthread_key_create(&thr_id_key, NULL);
|
||||
intercept_thread_id = (int*)malloc(sizeof(int));
|
||||
*intercept_thread_id = key;
|
||||
pthread_create(&intercept_thread, NULL, zts_start_core_service, (void *)(intercept_thread_id));
|
||||
}
|
||||
|
||||
//void init_service_and_rpc(int key, const char * path, const char * nwid) {
|
||||
// rpcNWID = nwid;
|
||||
// init_service(key, path);
|
||||
//}
|
||||
|
||||
// Enables or disables intercept for current thread using key in thread-local storage
|
||||
void set_intercept_status(int mode) {
|
||||
#if defined(__APPLE__)
|
||||
DEBUG_INFO("mode=%d, tid=%d", mode, pthread_mach_thread_np(pthread_self()));
|
||||
#else
|
||||
// fprintf(stderr, "set_intercept_status(mode=%d): tid = %d\n", mode, gettid());
|
||||
#endif
|
||||
pthread_key_create(&thr_id_key, NULL);
|
||||
intercept_thread_id = (int*)malloc(sizeof(int));
|
||||
*intercept_thread_id = mode;
|
||||
pthread_setspecific(thr_id_key, intercept_thread_id);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------ EXPORTED JNI METHODS --------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME
|
||||
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Starts a new service instance
|
||||
/* NOTE: Since on Android devices the sdcard is formatted as fat32, we can't use just any
|
||||
location to set up the RPC unix domain socket. Rather we must use the application's specific
|
||||
data directory given by getApplicationContext().getFilesDir() */
|
||||
JNIEXPORT int JNICALL Java_ZeroTier_ZTSDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path) {
|
||||
if(path)
|
||||
homeDir = env->GetStringUTFChars(path, NULL);
|
||||
zts_start_core_service(NULL);
|
||||
}
|
||||
// Shuts down ZeroTier service and SOCKS5 Proxy server
|
||||
JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1service(JNIEnv *env, jobject thisObj) {
|
||||
if(zt1Service)
|
||||
zts_stop_service();
|
||||
// TODO: Also terminate SOCKS5 Proxy
|
||||
// zts_stop_proxy_server();
|
||||
}
|
||||
// Returns whether the ZeroTier service is running
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1service_1is_1running(JNIEnv *env, jobject thisObj) {
|
||||
if(zt1Service)
|
||||
return zts_service_is_running();
|
||||
return false;
|
||||
}
|
||||
// Returns path for ZT config/data files
|
||||
JNIEXPORT jstring JNICALL Java_ZeroTier_ZTSDK_zt_1get_1homepath(JNIEnv *env, jobject thisObj) {
|
||||
return (*env).NewStringUTF(zts_get_homepath());
|
||||
}
|
||||
// Join a network
|
||||
JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1join_1network(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
const char *nwidstr;
|
||||
if(nwid) {
|
||||
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
||||
zts_join_network(nwidstr);
|
||||
}
|
||||
}
|
||||
// Leave a network
|
||||
JNIEXPORT void JNICALL Java_ZeroTier_ZTSDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
const char *nwidstr;
|
||||
if(nwid) {
|
||||
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
||||
zts_leave_network(nwidstr);
|
||||
}
|
||||
}
|
||||
// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations
|
||||
// Now only returns first assigned address per network. Shouldn't normally be a problem
|
||||
JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv4_1address(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
||||
char address_string[32];
|
||||
memset(address_string, 0, 32);
|
||||
zts_get_ipv4_address(nwid_str, address_string);
|
||||
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
||||
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
||||
jstring _str = (*env).NewStringUTF(address_string);
|
||||
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_ZeroTier_ZTSDK_zt_1get_1ipv6_1address(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
||||
char address_string[32];
|
||||
memset(address_string, 0, 32);
|
||||
zts_get_ipv6_address(nwid_str, address_string);
|
||||
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
||||
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
||||
jstring _str = (*env).NewStringUTF(address_string);
|
||||
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
// Returns the device is in integer form
|
||||
JNIEXPORT jint Java_ZeroTier_ZTSDK_zt_1get_1device_1id() {
|
||||
return zts_get_device_id();
|
||||
}
|
||||
// Returns whether the path to an endpoint is currently relayed by a root server
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1is_1relayed() {
|
||||
return zts_is_relayed();
|
||||
}
|
||||
// Starts a SOCKS5 proxy server for a given ZeroTier network
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1start_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) {
|
||||
const char *nwidstr = env->GetStringUTFChars(nwid, NULL);
|
||||
struct sockaddr_in addr;
|
||||
// GET ZTAddress fields
|
||||
jclass cls = env->GetObjectClass(ztaddr);
|
||||
jfieldID fid = env->GetFieldID(cls, "port", "I");
|
||||
addr.sin_port = htons(env->GetIntField(ztaddr, fid));
|
||||
fid = env->GetFieldID(cls, "_rawAddr", "J");
|
||||
addr.sin_addr.s_addr = env->GetLongField(ztaddr, fid);
|
||||
return zts_start_proxy_server((char *)zts_get_homepath, nwidstr, (struct sockaddr_storage *)&addr);
|
||||
}
|
||||
//
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1stop_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
return zts_stop_proxy_server((char*)env->GetStringUTFChars(nwid, NULL));
|
||||
}
|
||||
// Returns the local address of the SOCKS5 Proxy server
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1get_1proxy_1server_1address(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) {
|
||||
struct sockaddr_in addr;
|
||||
int err = zts_get_proxy_server_address(env->GetStringUTFChars(nwid, NULL), (struct sockaddr_storage*)&addr);
|
||||
// SET ZTAddress fields
|
||||
jfieldID fid;
|
||||
jclass cls = env->GetObjectClass(ztaddr);
|
||||
fid = env->GetFieldID(cls, "port", "I");
|
||||
env->SetIntField(ztaddr, fid, addr.sin_port);
|
||||
fid = env->GetFieldID(cls,"_rawAddr", "J");
|
||||
env->SetLongField(ztaddr, fid,addr.sin_addr.s_addr);
|
||||
return err;
|
||||
}
|
||||
//
|
||||
JNIEXPORT jboolean JNICALL Java_ZeroTier_ZTSDK_zt_1proxy_1is_1running(JNIEnv *env, jobject thisObj, jstring nwid) {
|
||||
// TODO: implement
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------- zts_start_core_service ---------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Starts a ZeroTier service in the background
|
||||
void *zts_start_core_service(void *thread_id) {
|
||||
|
||||
#if defined(SDK_BUNDLED)
|
||||
if(thread_id)
|
||||
homeDir = std::string((char*)thread_id);
|
||||
#endif
|
||||
|
||||
//#if defined(SDK_BUNDLED) && !defined(__ANDROID__)
|
||||
// set_intercept_status(INTERCEPT_DISABLED); // Ignore network calls from ZT service
|
||||
//#endif
|
||||
|
||||
#if defined(__IOS__)
|
||||
char current_dir[MAX_DIR_SZ];
|
||||
// Go to the app's data directory so we can shorten the sun_path we bind to
|
||||
getcwd(current_dir, MAX_DIR_SZ);
|
||||
std::string targetDir = homeDir; // + "/../../";
|
||||
chdir(targetDir.c_str());
|
||||
homeDir = localHomeDir;
|
||||
#endif
|
||||
|
||||
#if defined(__UNITY_3D__)
|
||||
char current_dir[MAX_DIR_SZ];
|
||||
getcwd(current_dir, MAX_DIR_SZ);
|
||||
chdir(service_path.c_str());
|
||||
homeDir = current_dir; // homeDir shall be current_dir
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
// homeDir = "dont/run/this/in/the/simulator/it/wont/work";
|
||||
#elif TARGET_OS_IPHONE
|
||||
localHomeDir = "ZeroTier/One";
|
||||
std::string del = givenHomeDir.length() && givenHomeDir[givenHomeDir.length()-1]!='/' ? "/" : "";
|
||||
homeDir = givenHomeDir + del + localHomeDir;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
localHomeDir = homeDir; // Used for RPC and *can* differ from homeDir on some platforms
|
||||
#endif
|
||||
|
||||
DEBUG_INFO("homeDir=%s", homeDir.c_str());
|
||||
// Where network .conf files will be stored
|
||||
netDir = homeDir + "/networks.d";
|
||||
zt1Service = (ZeroTier::OneService *)0;
|
||||
|
||||
// Construct path for network config and supporting service files
|
||||
if (homeDir.length()) {
|
||||
std::vector<std::string> hpsp(ZeroTier::OSUtils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"",""));
|
||||
std::string ptmp;
|
||||
if (homeDir[0] == ZT_PATH_SEPARATOR)
|
||||
ptmp.push_back(ZT_PATH_SEPARATOR);
|
||||
for(std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
|
||||
if (ptmp.length() > 0)
|
||||
ptmp.push_back(ZT_PATH_SEPARATOR);
|
||||
ptmp.append(*pi);
|
||||
if ((*pi != ".")&&(*pi != "..")) {
|
||||
if (!ZeroTier::OSUtils::mkdir(ptmp)) {
|
||||
DEBUG_ERROR("home path does not exist, and could not create");
|
||||
perror("error\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG_ERROR("homeDir is empty, could not construct path");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_INFO("starting service...");
|
||||
|
||||
// Generate random port for new service instance
|
||||
unsigned int randp = 0;
|
||||
ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
|
||||
int servicePort = 9000 + (randp % 1000);
|
||||
|
||||
for(;;) {
|
||||
zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort);
|
||||
switch(zt1Service->run()) {
|
||||
case ZeroTier::OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
|
||||
case ZeroTier::OneService::ONE_NORMAL_TERMINATION:
|
||||
break;
|
||||
case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR:
|
||||
DEBUG_ERROR("fatal error: %s",zt1Service->fatalErrorMessage().c_str());
|
||||
break;
|
||||
case ZeroTier::OneService::ONE_IDENTITY_COLLISION: {
|
||||
delete zt1Service;
|
||||
zt1Service = (ZeroTier::OneService *)0;
|
||||
std::string oldid;
|
||||
ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
|
||||
if (oldid.length()) {
|
||||
ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
|
||||
ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
|
||||
ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
|
||||
}
|
||||
}
|
||||
continue; // restart!
|
||||
}
|
||||
break; // terminate loop -- normally we don't keep restarting
|
||||
}
|
||||
delete zt1Service;
|
||||
zt1Service = (ZeroTier::OneService *)0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
887
src/sockets.c
887
src/sockets.c
@@ -1,887 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifdef USE_GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
// For defining the Android direct-call API
|
||||
#if defined(__ANDROID__)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
//#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/errno.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/net.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#define SOCK_MAX (SOCK_PACKET + 1)
|
||||
#endif
|
||||
#define SOCK_TYPE_MASK 0xf
|
||||
|
||||
#include "sdk.h"
|
||||
#include "debug.h"
|
||||
#include "rpc.h"
|
||||
#include "defs.h"
|
||||
|
||||
#include "Constants.hpp" // For Tap's MTU
|
||||
|
||||
// Prototypes
|
||||
char *api_netpath = (char *)0;
|
||||
void load_symbols();
|
||||
void load_symbols_rpc();
|
||||
int (*realclose)(CLOSE_SIG);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- zt_init_rpc -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
int service_initialized = 0;
|
||||
|
||||
// Assembles (and/or) sets the RPC path for communication with the ZeroTier service
|
||||
void zts_init_rpc(const char *path, const char *nwid)
|
||||
{
|
||||
#if !defined(__IOS__)
|
||||
// Since we don't use function interposition in iOS
|
||||
if(!realconnect) {
|
||||
load_symbols_rpc();
|
||||
}
|
||||
#endif
|
||||
// If no path, construct one or get it fron system env vars
|
||||
if(!api_netpath) {
|
||||
rpc_mutex_init();
|
||||
// Provided by user
|
||||
#if defined(SDK_BUNDLED)
|
||||
// Get the path/nwid from the user application
|
||||
// netpath = [path + "/nc_" + nwid]
|
||||
char *fullpath = (char *)malloc(strlen(path)+strlen(nwid)+1+4);
|
||||
if(fullpath) {
|
||||
zts_join_network_soft(path, nwid);
|
||||
strcpy(fullpath, path);
|
||||
strcat(fullpath, "/nc_");
|
||||
strcat(fullpath, nwid);
|
||||
api_netpath = fullpath;
|
||||
}
|
||||
// Provided by Env
|
||||
#else
|
||||
// Get path/nwid from environment variables
|
||||
if (!api_netpath) {
|
||||
api_netpath = getenv("ZT_NC_NETWORK");
|
||||
DEBUG_INFO("$ZT_NC_NETWORK=%s", api_netpath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// start the SDK service if this is bundled
|
||||
#if defined(SDK_BUNDLED)
|
||||
if(!service_initialized) {
|
||||
DEBUG_ATTN("api_netpath = %s", api_netpath);
|
||||
pthread_t intercept_thread;
|
||||
pthread_create(&intercept_thread, NULL, zts_start_core_service, (void *)(path));
|
||||
service_initialized = 1;
|
||||
DEBUG_ATTN("waiting for service to assign address to network stack");
|
||||
// wait for zt service to assign the network stack an address
|
||||
sleep(1);
|
||||
while(!zts_has_address(nwid)) { usleep(1000); }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void get_api_netpath() { zts_init_rpc("",""); }
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ send() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const void *buf, size_t len
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags)
|
||||
{
|
||||
jbyte *body = (*env)->GetByteArrayElements(env, buf, 0);
|
||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||
memcpy(bufp, body, len);
|
||||
(*env)->ReleaseByteArrayElements(env, buf, body, 0);
|
||||
int written_bytes = write(fd, body, len);
|
||||
return written_bytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ sendto() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const void *buf, size_t len, int flags,
|
||||
// const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// TODO: Check result of each JNI call
|
||||
// UDP TX
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1sendto(
|
||||
JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
jclass cls = (*env)->GetObjectClass(env, ztaddr);
|
||||
jfieldID f = (*env)->GetFieldID(env, cls, "port", "I");
|
||||
addr.sin_port = htons((*env)->GetIntField(env, ztaddr, f));
|
||||
f = (*env)->GetFieldID(env, cls, "_rawAddr", "J");
|
||||
addr.sin_addr.s_addr = (*env)->GetLongField(env, ztaddr, f);
|
||||
addr.sin_family = AF_INET;
|
||||
//LOGV("zt_sendto(): fd = %d\naddr = %s\nport=%d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||
// TODO: Optimize this
|
||||
jbyte *body = (*env)->GetByteArrayElements(env, buf, 0);
|
||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||
memcpy(bufp, body, len);
|
||||
(*env)->ReleaseByteArrayElements(env, buf, body, 0);
|
||||
// "connect" and send buffer contents
|
||||
int sent_bytes = zts_sendto(fd, body, len, flags, (struct sockaddr *)&addr, sizeof(addr));
|
||||
return sent_bytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
//#if !defined(__ANDROID__)
|
||||
#ifdef DYNAMIC_LIB
|
||||
ssize_t zt_sendto(SENDTO_SIG) // Exposed as API
|
||||
#else
|
||||
ssize_t zts_sendto(SENDTO_SIG) // Used as internal implementation
|
||||
#endif
|
||||
{
|
||||
if(len > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
|
||||
errno = EMSGSIZE; // Msg is too large
|
||||
return -1;
|
||||
}
|
||||
int socktype = 0;
|
||||
socklen_t socktype_len;
|
||||
getsockopt(fd,SOL_SOCKET, SO_TYPE, (void*)&socktype, &socktype_len);
|
||||
|
||||
if((socktype & SOCK_STREAM) || (socktype & SOCK_SEQPACKET)) {
|
||||
if(addr == NULL || flags != 0) {
|
||||
errno = EISCONN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// EMSGSIZE should be returned if the message is too long to be passed atomically through
|
||||
// the underlying protocol, in our case MTU?
|
||||
// TODO: More efficient solution
|
||||
// This connect call is used to get the address info to the stack for sending the packet
|
||||
int err;
|
||||
if((err = zts_connect(fd, addr, addrlen)) < 0) {
|
||||
DEBUG_ERROR("unknown problem passing address info to stack");
|
||||
errno = EISCONN; // double-check this is correct
|
||||
return -1;
|
||||
}
|
||||
return write(fd, buf, len);
|
||||
}
|
||||
//#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- sendmsg() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct msghdr *msg, int flags
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#ifdef DYNAMIC_LIB
|
||||
ssize_t zt_sendmsg(SENDMSG_SIG)
|
||||
#else
|
||||
ssize_t zts_sendmsg(SENDMSG_SIG)
|
||||
#endif
|
||||
{
|
||||
//DEBUG_EXTRA("fd=%d",fd);
|
||||
char * p, * buf;
|
||||
size_t tot_len = 0;
|
||||
size_t err;
|
||||
struct iovec * iov = msg->msg_iov;
|
||||
for(int i=0; i<msg->msg_iovlen; ++i)
|
||||
tot_len += iov[i].iov_len;
|
||||
if(tot_len > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
|
||||
errno = EMSGSIZE; // Message too large to send atomically via underlying protocol, don't send
|
||||
return -1;
|
||||
}
|
||||
buf = (char *)malloc(tot_len);
|
||||
if(tot_len != 0 && buf == NULL) {
|
||||
errno = ENOMEM; // Unable to allocate space for message
|
||||
return -1;
|
||||
}
|
||||
p = buf;
|
||||
for(int i=0; i < msg->msg_iovlen; ++i) {
|
||||
memcpy(p, iov[i].iov_base, iov[i].iov_len);
|
||||
p += iov[i].iov_len;
|
||||
}
|
||||
#if defined(__cplusplus)
|
||||
#if defined(__APPLE__)
|
||||
err = sendto(fd, buf, tot_len, flags, (const struct sockaddr *)(msg->msg_name), msg->msg_namelen);
|
||||
#elif defined (__linux__)
|
||||
err = sendto(fd, buf, tot_len, flags, (__CONST_SOCKADDR_ARG)(msg->msg_name), msg->msg_namelen);
|
||||
#endif
|
||||
#else
|
||||
err = sendto(fd, buf, tot_len, flags, msg->msg_name, msg->msg_namelen);
|
||||
#endif
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- recvfrom() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, void *restrict buf, size_t len, int flags, struct sockaddr
|
||||
// *restrict addr, socklen_t *restrict addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// UDP RX
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1recvfrom(
|
||||
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len, jint flags, jobject ztaddr)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
jbyte *body = (*env)->GetByteArrayElements(env, buf, 0);
|
||||
unsigned char buffer[SDK_MTU];
|
||||
int payload_offset = sizeof(int) + sizeof(struct sockaddr_storage);
|
||||
int rxbytes = zts_recvfrom(fd, &buffer, len, flags, &addr, sizeof(struct sockaddr_storage));
|
||||
if(rxbytes > 0)
|
||||
memcpy(body, (jbyte*)buffer + payload_offset, rxbytes);
|
||||
(*env)->ReleaseByteArrayElements(env, buf, body, 0);
|
||||
// Update fields of Java ZTAddress object
|
||||
jfieldID fid;
|
||||
jclass cls = (*env)->GetObjectClass(env, ztaddr);
|
||||
fid = (*env)->GetFieldID(env, cls, "port", "I");
|
||||
(*env)->SetIntField(env, ztaddr, fid, addr.sin_port);
|
||||
fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J");
|
||||
(*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr);
|
||||
return rxbytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
//#if !defined(__ANDROID__)
|
||||
#ifdef DYNAMIC_LIB
|
||||
ssize_t zt_recvfrom(RECVFROM_SIG)
|
||||
#else
|
||||
ssize_t zts_recvfrom(RECVFROM_SIG)
|
||||
#endif
|
||||
{
|
||||
int read_chunk_sz = 0, payload_offset, tmpsz=0, pnum=0; // payload size
|
||||
char tmpbuf[SDK_MTU];
|
||||
memset(tmpbuf, 0, SDK_MTU);
|
||||
|
||||
// Attempt to read SDK_MTU sized chunk
|
||||
int total_read = 0, n=0;
|
||||
|
||||
// Read the entire SDK_MTU-sized chunk from the service socket
|
||||
while(total_read < SDK_MTU) {
|
||||
n = read(fd, tmpbuf+total_read, SDK_MTU);
|
||||
|
||||
if(n>0) {
|
||||
total_read += n;
|
||||
}
|
||||
else if (n < 0)
|
||||
return n;
|
||||
}
|
||||
|
||||
if(n > 0) {
|
||||
// For cases where *addrlen is an unreasonable value
|
||||
// FIXME: This should probably have some more thought put into it
|
||||
*addrlen = *addrlen > SDK_MTU ? 0 : *addrlen;
|
||||
|
||||
memcpy(addr, tmpbuf, *addrlen);
|
||||
memcpy(&tmpsz, tmpbuf + sizeof(struct sockaddr_storage), sizeof(tmpsz));
|
||||
memcpy(&pnum, tmpbuf + sizeof(struct sockaddr_storage) + sizeof(int), sizeof(int));
|
||||
if(tmpsz > SDK_MTU || tmpsz < 0) {
|
||||
DEBUG_ERROR("An error occured somewhere in the SDK, read=%d", n);
|
||||
return -1;
|
||||
}
|
||||
payload_offset = sizeof(int) + sizeof(struct sockaddr_storage);
|
||||
|
||||
// No matter how much we read from the service, only copy 'read_chunk_sz'
|
||||
// into the app's buffer
|
||||
read_chunk_sz = len < SDK_MTU ? len : SDK_MTU;
|
||||
read_chunk_sz = tmpsz < read_chunk_sz ? tmpsz : read_chunk_sz; // FIXME
|
||||
memcpy(buf, tmpbuf + payload_offset, read_chunk_sz);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
return read_chunk_sz;
|
||||
}
|
||||
//#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- recvmsg() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct msghdr *msg, int flags
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#ifdef DYNAMIC_LIB
|
||||
ssize_t zt_recvmsg(RECVMSG_SIG)
|
||||
#else
|
||||
ssize_t zts_recvmsg(RECVMSG_SIG)
|
||||
#endif
|
||||
{
|
||||
//DEBUG_EXTRA("fd=%d", fd);
|
||||
ssize_t err, n, tot_len = 0;
|
||||
char *buf, *p;
|
||||
struct iovec *iov = msg->msg_iov;
|
||||
|
||||
for(int i = 0; i < msg->msg_iovlen; ++i)
|
||||
tot_len += iov[i].iov_len;
|
||||
buf = (char *)malloc(tot_len);
|
||||
if(tot_len != 0 && buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
#if defined(__cplusplus)
|
||||
#if defined(__APPLE__)
|
||||
n = err = recvfrom(fd, buf, tot_len, flags, (struct sockaddr * __restrict)(msg->msg_name), &msg->msg_namelen);
|
||||
#elif defined(__linux__)
|
||||
n = err = recvfrom(fd, buf, tot_len, flags, (__SOCKADDR_ARG)(msg->msg_name), &msg->msg_namelen);
|
||||
#endif
|
||||
#else
|
||||
n = err = recvfrom(fd, buf, tot_len, flags, msg->msg_name, &msg->msg_namelen);
|
||||
#endif
|
||||
p = buf;
|
||||
|
||||
// According to: http://pubs.opengroup.org/onlinepubs/009695399/functions/recvmsg.html
|
||||
if(err > msg->msg_controllen && !( msg->msg_flags & MSG_PEEK)) {
|
||||
// excess data should be disgarded
|
||||
msg->msg_flags |= MSG_TRUNC; // Indicate that the buffer has been truncated
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
ssize_t count = n < iov->iov_len ? n : iov->iov_len;
|
||||
memcpy (iov->iov_base, p, count);
|
||||
p += count;
|
||||
n -= count;
|
||||
++iov;
|
||||
}
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------- Exposed RX/TX API for .NET Wrapper ---------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__UNITY_3D__)
|
||||
// Just expose some basic calls for configuring and RX/TXing through ZT sockets
|
||||
ssize_t zt_send(int fd, void *buf, int len) {
|
||||
return write(fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t zt_recv(int fd, void *buf, int len) {
|
||||
return read(fd, buf, len);
|
||||
}
|
||||
|
||||
int zt_set_nonblock(int fd) {
|
||||
return fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------- Exposed RX/TX API for Java JNI -----------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// TCP TX
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len)
|
||||
{
|
||||
jbyte *body = (*env)->GetByteArrayElements(env, buf, 0);
|
||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||
memcpy(bufp, body, len);
|
||||
(*env)->ReleaseByteArrayElements(env, buf, body, 0);
|
||||
int written_bytes = write(fd, body, len);
|
||||
return written_bytes;
|
||||
}
|
||||
// TCP RX
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len)
|
||||
{
|
||||
jbyte *body = (*env)->GetByteArrayElements(env, buf, 0);
|
||||
int read_bytes = read(fd, body, len);
|
||||
(*env)->ReleaseByteArrayElements(env, buf, body, 0);
|
||||
return read_bytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------------- setsockopt() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int level, int optname, const void *optval, socklen_t optlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1setsockopt(
|
||||
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) {
|
||||
return zts_setsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_setsockopt(SETSOCKOPT_SIG)
|
||||
#else
|
||||
int zts_setsockopt(SETSOCKOPT_SIG)
|
||||
#endif
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// --------------------------------- getsockopt() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int level, int optname, void *optval, socklen_t *optlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockopt(
|
||||
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) {
|
||||
return zts_getsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_getsockopt(GETSOCKOPT_SIG)
|
||||
#else
|
||||
int zts_getsockopt(GETSOCKOPT_SIG)
|
||||
#endif
|
||||
{
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
if(optname == SO_TYPE) {
|
||||
int* val = (int*)optval;
|
||||
*val = 2;
|
||||
optval = (void*)val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- socket() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int socket_family, int socket_type, int protocol
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol) {
|
||||
return zts_socket(family, type, protocol);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_socket(SOCKET_SIG)
|
||||
#else
|
||||
int zts_socket(SOCKET_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("");
|
||||
// Check that type makes sense
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
int flags = socket_type & ~SOCK_TYPE_MASK;
|
||||
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
socket_type &= SOCK_TYPE_MASK;
|
||||
// Check protocol is in range
|
||||
#if defined(__linux__)
|
||||
if (socket_family < 0 || socket_family >= NPROTO){
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
if (socket_type < 0 || socket_type >= SOCK_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
// Assemble and send RPC
|
||||
struct socket_st rpc_st;
|
||||
rpc_st.socket_family = socket_family;
|
||||
rpc_st.socket_type = socket_type;
|
||||
rpc_st.protocol = protocol;
|
||||
// -1 is passed since we we're generating the new socket in this call
|
||||
int err = rpc_send_command(api_netpath, RPC_SOCKET, -1, &rpc_st, sizeof(struct socket_st));
|
||||
DEBUG_INFO("err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- connect() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) {
|
||||
struct sockaddr_in addr;
|
||||
const char *str = (*env)->GetStringUTFChars(env, addrstr, 0);
|
||||
addr.sin_addr.s_addr = inet_addr(str);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons( port );
|
||||
(*env)->ReleaseStringUTFChars(env, addrstr, str);
|
||||
return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_connect(CONNECT_SIG)
|
||||
#else
|
||||
int zts_connect(CONNECT_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
struct connect_st rpc_st;
|
||||
rpc_st.fd = fd;
|
||||
memcpy(&rpc_st.addr, addr, sizeof(struct sockaddr_storage));
|
||||
memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t));
|
||||
return rpc_send_command(api_netpath, RPC_CONNECT, fd, &rpc_st, sizeof(struct connect_st));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ bind() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, const struct sockaddr *addr, socklen_t addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) {
|
||||
struct sockaddr_in addr;
|
||||
const char *str = (*env)->GetStringUTFChars(env, addrstr, 0);
|
||||
DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port);
|
||||
addr.sin_addr.s_addr = inet_addr(str);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons( port );
|
||||
(*env)->ReleaseStringUTFChars(env, addrstr, str);
|
||||
return zts_bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_bind(BIND_SIG)
|
||||
#else
|
||||
int zts_bind(BIND_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
struct bind_st rpc_st;
|
||||
rpc_st.fd = fd;
|
||||
memcpy(&rpc_st.addr, addr, sizeof(struct sockaddr_storage));
|
||||
memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t));
|
||||
return rpc_send_command(api_netpath, RPC_BIND, fd, &rpc_st, sizeof(struct bind_st));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- accept4() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct sockaddr *addr, socklen_t *addrlen, int flags
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept4(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port, jint flags) {
|
||||
struct sockaddr_in addr;
|
||||
char *str;
|
||||
// = env->GetStringUTFChars(addrstr, NULL);
|
||||
(*env)->ReleaseStringUTFChars(env, addrstr, str);
|
||||
addr.sin_addr.s_addr = inet_addr(str);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons( port );
|
||||
return zts_accept4(fd, (struct sockaddr *)&addr, sizeof(addr), flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_accept4(ACCEPT4_SIG)
|
||||
#else
|
||||
int zts_accept4(ACCEPT4_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
#if !defined(__ANDROID__)
|
||||
if ((flags & SOCK_CLOEXEC))
|
||||
fcntl(fd, F_SETFL, FD_CLOEXEC);
|
||||
if ((flags & SOCK_NONBLOCK))
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
addrlen = !addr ? 0 : addrlen;
|
||||
return accept(fd, addr, addrlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- accept() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd struct sockaddr *addr, socklen_t *addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1accept(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) {
|
||||
struct sockaddr_in addr;
|
||||
// TODO: Send addr info back to Javaland
|
||||
addr.sin_addr.s_addr = inet_addr("");
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons( port );
|
||||
return zts_accept(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_accept(ACCEPT_SIG)
|
||||
#else
|
||||
int zts_accept(ACCEPT_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
#if !defined(__UNITY_3D__)
|
||||
if(addr)
|
||||
addr->sa_family = AF_INET;
|
||||
#endif
|
||||
int new_fd = get_new_fd(fd);
|
||||
DEBUG_INFO("newfd=%d", new_fd);
|
||||
|
||||
if(new_fd > 0) {
|
||||
errno = ERR_OK;
|
||||
return new_fd;
|
||||
}
|
||||
errno = EAGAIN;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------- listen()--------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int backlog
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog) {
|
||||
return zts_listen(fd, backlog);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_listen(LISTEN_SIG)
|
||||
#else
|
||||
int zts_listen(LISTEN_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
struct listen_st rpc_st;
|
||||
rpc_st.fd = fd;
|
||||
rpc_st.backlog = backlog;
|
||||
return rpc_send_command(api_netpath, RPC_LISTEN, fd, &rpc_st, sizeof(struct listen_st));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------- close() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1close(JNIEnv *env, jobject thisObj, jint fd) {
|
||||
return zts_close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_close(CLOSE_SIG)
|
||||
#else
|
||||
int zts_close(CLOSE_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_INFO("fd=%d", fd);
|
||||
return realclose(fd);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// -------------------------------- getsockname() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) {
|
||||
struct sockaddr_in addr;
|
||||
int err = zts_getsockname(fd, &addr, sizeof(struct sockaddr));
|
||||
jfieldID fid;
|
||||
jclass cls = (*env)->GetObjectClass(env, ztaddr);
|
||||
fid = (*env)->GetFieldID(env, cls, "port", "I");
|
||||
(*env)->SetIntField(env, ztaddr, fid, addr.sin_port);
|
||||
fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J");
|
||||
(*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_getsockname(GETSOCKNAME_SIG)
|
||||
#else
|
||||
int zts_getsockname(GETSOCKNAME_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_EXTRA("fd=%d", fd);
|
||||
struct getsockname_st rpc_st;
|
||||
rpc_st.fd = fd;
|
||||
memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t));
|
||||
int rpcfd = rpc_send_command(api_netpath, RPC_GETSOCKNAME, fd, &rpc_st, sizeof(struct getsockname_st));
|
||||
// read address info from service
|
||||
char addrbuf[sizeof(struct sockaddr_storage)];
|
||||
memset(&addrbuf, 0, sizeof(struct sockaddr_storage));
|
||||
if(rpcfd > -1) {
|
||||
int err = read(rpcfd, &addrbuf, sizeof(struct sockaddr));
|
||||
close(rpcfd);
|
||||
if(err > 0) {
|
||||
int sum=0;
|
||||
for(int i=0;i<sizeof(struct sockaddr_storage);i++) {
|
||||
sum|=addrbuf[i];
|
||||
}
|
||||
if(!sum) { // RXed a zero-ed address buffer, currently the only way to signal a problem
|
||||
errno = ENOTSOCK; // TODO: general error, needs to be more specific
|
||||
DEBUG_ERROR("no address info given by service.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errno = ENOTSOCK; // TODO: general error, needs to be more specific
|
||||
DEBUG_ERROR("unable to read address info from service. err=%d", err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
struct sockaddr_storage sock_storage;
|
||||
memcpy(&sock_storage, addrbuf, sizeof(struct sockaddr));
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
memcpy(addr, &sock_storage, sizeof(struct sockaddr));
|
||||
addr->sa_family = AF_INET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// -------------------------------- getpeername() -------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, struct sockaddr *addr, socklen_t *addrlen
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) {
|
||||
struct sockaddr_in addr;
|
||||
int err = zts_getpeername(fd, &addr, sizeof(struct sockaddr));
|
||||
jfieldID fid;
|
||||
jclass cls = (*env)->GetObjectClass(env, ztaddr);
|
||||
fid = (*env)->GetFieldID(env, cls, "port", "I");
|
||||
(*env)->SetIntField(env, ztaddr, fid, addr.sin_port);
|
||||
fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J");
|
||||
(*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_getpeername(GETSOCKNAME_SIG)
|
||||
#else
|
||||
int zts_getpeername(GETSOCKNAME_SIG)
|
||||
#endif
|
||||
{
|
||||
get_api_netpath();
|
||||
DEBUG_EXTRA("fd=%d", fd);
|
||||
struct getsockname_st rpc_st;
|
||||
rpc_st.fd = fd;
|
||||
memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t));
|
||||
int rpcfd = rpc_send_command(api_netpath, RPC_GETPEERNAME, fd, &rpc_st, sizeof(struct getsockname_st));
|
||||
// read address info from service
|
||||
char addrbuf[sizeof(struct sockaddr_storage)];
|
||||
memset(&addrbuf, 0, sizeof(struct sockaddr_storage));
|
||||
|
||||
if(rpcfd > -1) {
|
||||
int err = read(rpcfd, &addrbuf, sizeof(struct sockaddr));
|
||||
close(rpcfd);
|
||||
if(err > 0) {
|
||||
int sum=0;
|
||||
for(int i=0;i<sizeof(struct sockaddr_storage);i++) {
|
||||
sum|=addrbuf[i];
|
||||
}
|
||||
if(!sum) { // RXed a zero-ed address buffer, currently the only way to signal a problem
|
||||
errno = ENOTSOCK; // TODO: general error, needs to be more specific
|
||||
DEBUG_ERROR("no address info given by service.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errno = ENOTSOCK; // TODO: general error, needs to be more specific
|
||||
DEBUG_ERROR("unable to read address info from service. err=%d", err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
struct sockaddr_storage sock_storage;
|
||||
memcpy(&sock_storage, addrbuf, sizeof(struct sockaddr));
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
memcpy(addr, &sock_storage, sizeof(struct sockaddr));
|
||||
addr->sa_family = AF_INET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ fcntl() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
// int fd, int cmd, int flags
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
JNIEXPORT jint JNICALL Java_ZeroTier_ZTSDK_zt_1fcntl(JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags) {
|
||||
return zts_fcntl(fd,cmd,flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAMIC_LIB
|
||||
int zt_fcntl(FCNTL_SIG)
|
||||
#else
|
||||
int zts_fcntl(FCNTL_SIG)
|
||||
#endif
|
||||
{
|
||||
DEBUG_EXTRA("fd=%d, cmd=%d, flags=%d", fd, cmd, flags);
|
||||
return fcntl(fd,cmd,flags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
Hot-Swappable Network Stacks!
|
||||
====
|
||||
|
||||
We've now enabled the ability for users to build the ZeroTier SDK with different network stacks with the mere flip of a compiler flag as well as running different stacks concurrently! This is perfect for embedded developers which may need a smaller code footprint and would like to use their own smaller or more specialized network stacks.
|
||||
|
||||
`SDK_LWIP=1` and `SDK_PICOTCP=1` will enable the lwIP and picoTCP network stacks respectively.
|
||||
|
||||
Currently our *lwIP* stack driver supports IPV4 and limited IPV6, whereas our *picoTCP* stack driver supports both IPV4 and IPV6 with no known issues.
|
||||
|
||||
To enable specific protocol versions use `SDK_IPV4=1` and `SDK_IPV6=1` in conjunction with the above stack selection flags.
|
||||
|
||||
Also, to enable debug for the SDK use `SDK_DEBUG=1`, to enable debug for the *lwIP* stack use `SDK_LWIP_DEBUG=1`.
|
||||
|
||||
## Integrating Your Own Custom Stack
|
||||
|
||||
If you don't know why this section exists, then I suggest turning back now. This is not for you. Otherwise, let's get on with things, here's how you can integrate your own custom network stack if for some reason lwIP or picoTCP aren't cutting it for you:
|
||||
|
||||
Investigate the structure of `src/tap.cpp`, this file contains calls to functions implemented in the stack driver code (located in `src/stack_drivers`).
|
||||
|
||||
Each stack is different but generally you'll need to provide:
|
||||
- An initialization function to configure and bring up the stack's `interface` (or similar).
|
||||
- An I/O polling loop section where you'll execute your timer calls, and check for inbound and outbound frames.
|
||||
- A low-level input and output function to handle feeding ethernet frames into and out of the stack in its own unique way.
|
||||
- Calls to your stack's API which roughly correspond with `handleRead()`, `handleWrite()`, `handleSocket()`, `handleConnect()`, etc
|
||||
- In those calls you'll need to handle the creation, management, and destruction of your stack's "connection" objects, whatever that may be.
|
||||
@@ -1,4 +0,0 @@
|
||||
jIP Network Stack Driver
|
||||
====
|
||||
|
||||
This section only exists as minimal example of how a network stack would interact with the ZeroTier ethernet tap service. See the `lwIP` and `picoTCP` driver sections for full implementations of a stack driver.
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#if defined(SDK_JIP)
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
void jip_init_interface(NetconEthernetTap *tap, const InetAddress &ip)
|
||||
{
|
||||
// initialize your stack here
|
||||
}
|
||||
|
||||
void jip_loop(NetconEthernetTap *tap)
|
||||
{
|
||||
while(_run)
|
||||
{
|
||||
// Tick stack timers here
|
||||
// Perhaps do some polling?
|
||||
}
|
||||
}
|
||||
|
||||
void jip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
||||
{
|
||||
// RX packets here
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDK_JIP
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef SDK_JIPSTACK_H
|
||||
#define SDK_JIPSTACK_H
|
||||
|
||||
#if defined(SDK_JIP)
|
||||
|
||||
#include "Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef D_GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
void jip_init_interface(NetconEthernetTap *tap, const InetAddress &ip);
|
||||
void jip_loop(NetconEthernetTap *tap);
|
||||
void jip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
|
||||
/**
|
||||
* Loads an instance of picoTCP stack library in a private memory arena
|
||||
*
|
||||
* This uses dlmopen() to load an instance of the LWIP stack into its
|
||||
* own private memory space. This is done to get around the stack's
|
||||
* lack of thread-safety or multi-instance support. The alternative
|
||||
* would be to massively refactor the stack so everything lives in a
|
||||
* state object instead of static memory space.
|
||||
*/
|
||||
class jip_stack
|
||||
{
|
||||
public:
|
||||
|
||||
void *_libref;
|
||||
|
||||
void close() {
|
||||
#if defined(__STATIC_STACK__)
|
||||
return;
|
||||
#elif defined(__DYNAMIC_STACK__)
|
||||
dlclose(_libref);
|
||||
#endif
|
||||
}
|
||||
|
||||
//void (*_netif_init)(void);
|
||||
|
||||
Mutex _lock;
|
||||
Mutex _lock_mem;
|
||||
|
||||
jip_stack(const char* path) :
|
||||
_libref(NULL)
|
||||
{
|
||||
#if defined(__ANDROID__) || defined(__UNITY_3D__)
|
||||
#define __STATIC_STACK__
|
||||
#elif defined(__linux__)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load liblwip.so
|
||||
_libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW);
|
||||
#elif defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#include "node/Mutex.hpp"
|
||||
#define __STATIC_STACK__
|
||||
// iOS Simulator or iOS device
|
||||
// Do nothing, symbols are statically-linked
|
||||
#elif TARGET_OS_MAC && !defined(SDK_BUNDLED)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load liblwip.so
|
||||
_libref = dlopen(path, RTLD_NOW);
|
||||
#else
|
||||
#define __STATIC_STACK__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __STATIC_STACK__ // Set static references (for use in iOS)
|
||||
|
||||
//_netif_init = (void(*)(void))&netif_init;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications)
|
||||
|
||||
if(_libref == NULL)
|
||||
DEBUG_ERROR("dlerror(): %s", dlerror());
|
||||
|
||||
//_netif_init = (void(*)(void))dlsym(_libref, "netif_init");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~jip_stack()
|
||||
{
|
||||
if (_libref)
|
||||
dlclose(_libref);
|
||||
}
|
||||
|
||||
//inline void __netif_init(void) throw() { Mutex::Lock _l(_lock); _netif_init(); }
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // SDK_JIP
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
lwIP Network Stack Driver
|
||||
====
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,534 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef SDK_LWIPSTACK_H
|
||||
#define SDK_LWIPSTACK_H
|
||||
|
||||
#if defined (SDK_LWIP)
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
|
||||
#include "Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "tap.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
class NetconEthernetTap;
|
||||
struct Connection;
|
||||
|
||||
void lwip_init_interface(NetconEthernetTap *tap, const InetAddress &ip);
|
||||
void lwip_loop(NetconEthernetTap *tap);
|
||||
void lwip_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
Connection *lwip_handleSocket(NetconEthernetTap *tap, PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
|
||||
Connection * lwip_handleSocketProxy(NetconEthernetTap *tap, PhySocket *sock, int socket_type);
|
||||
void lwip_handleConnect(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc);
|
||||
int lwip_handleConnectProxy(NetconEthernetTap *tap, PhySocket *sock, struct sockaddr_in *rawAddr);
|
||||
void lwip_handleBind(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc);
|
||||
void lwip_handleListen(NetconEthernetTap *tap, PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc);
|
||||
void lwip_handleRead(NetconEthernetTap *tap, PhySocket *sock, void **uptr, bool lwip_invoked);
|
||||
void lwip_handleWrite(NetconEthernetTap *tap, Connection *conn);
|
||||
void lwip_handleClose(NetconEthernetTap *tap, PhySocket *sock, Connection *conn);
|
||||
|
||||
|
||||
|
||||
err_t tapif_init(struct netif *netif);
|
||||
err_t low_level_output(struct netif *netif, struct pbuf *p);
|
||||
|
||||
/*
|
||||
* Callback from LWIP for when data is available to be read from the network.
|
||||
*
|
||||
* Data is in the form of a linked list of struct pbufs, it is then recombined and
|
||||
* send to the client over the associated unix socket.
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param allocated PCB
|
||||
* @param chain of pbufs
|
||||
* @param error code
|
||||
* @return ERR_OK if everything is ok, -1 otherwise
|
||||
*
|
||||
*/
|
||||
err_t nc_recved(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err);
|
||||
|
||||
/*
|
||||
* Callback from LWIP for when a connection has been accepted and the PCB has been
|
||||
* put into an ACCEPT state.
|
||||
*
|
||||
* A socketpair is created, one end is kept and wrapped into a PhySocket object
|
||||
* for use in the main ZT I/O loop, and one end is sent to the client. The client
|
||||
* is then required to tell the service what new file descriptor it has allocated
|
||||
* for this connection. After the mapping is complete, the accepted socket can be
|
||||
* used.
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param newly allocated PCB
|
||||
* @param error code
|
||||
* @return ERR_OK if everything is ok, -1 otherwise
|
||||
*
|
||||
* i := should be implemented in intercept lib
|
||||
* I := is implemented in intercept lib
|
||||
* X := is implemented in service
|
||||
* ? := required treatment Unknown
|
||||
* - := Not needed
|
||||
*
|
||||
* [ ] EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and no connections are present
|
||||
* to be accepted. POSIX.1-2001 allows either error to be returned for
|
||||
* this case, and does not require these constants to have the same value,
|
||||
* so a portable application should check for both possibilities.
|
||||
* [I] EBADF - The descriptor is invalid.
|
||||
* [I] ECONNABORTED - A connection has been aborted.
|
||||
* [i] EFAULT - The addr argument is not in a writable part of the user address space.
|
||||
* [-] EINTR - The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).
|
||||
* [I] EINVAL - Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
|
||||
* [I] EINVAL - (accept4()) invalid value in flags.
|
||||
* [I] EMFILE - The per-process limit of open file descriptors has been reached.
|
||||
* [ ] ENFILE - The system limit on the total number of open files has been reached.
|
||||
* [ ] ENOBUFS, ENOMEM - Not enough free memory. This often means that the memory allocation is
|
||||
* limited by the socket buffer limits, not by the system memory.
|
||||
* [I] ENOTSOCK - The descriptor references a file, not a socket.
|
||||
* [I] EOPNOTSUPP - The referenced socket is not of type SOCK_STREAM.
|
||||
* [ ] EPROTO - Protocol error.
|
||||
*
|
||||
*/
|
||||
err_t nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err);
|
||||
|
||||
|
||||
err_t nc_recved_proxy(void *arg, struct tcp_pcb *PCB, struct pbuf *p, err_t err);
|
||||
void nc_udp_recved(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port);
|
||||
|
||||
|
||||
/*
|
||||
* Callback from LWIP when an internal error is associtated with the given (arg)
|
||||
*
|
||||
* Since the PCB related to this error might no longer exist, only its perviously
|
||||
* associated (arg) is provided to us.
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param error code
|
||||
*
|
||||
*/
|
||||
void nc_err(void *arg, err_t err);
|
||||
|
||||
/*
|
||||
* Callback from LWIP to do whatever work we might need to do.
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param PCB we're polling on
|
||||
* @return ERR_OK if everything is ok, -1 otherwise
|
||||
*
|
||||
*/
|
||||
err_t nc_poll(void* arg, struct tcp_pcb *PCB);
|
||||
|
||||
/*
|
||||
* Callback from LWIP to signal that 'len' bytes have successfully been sent.
|
||||
* As a result, we should put our socket back into a notify-on-readability state
|
||||
* since there is now room on the PCB buffer to write to.
|
||||
*
|
||||
* NOTE: This could be used to track the amount of data sent by a connection.
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param relevant PCB
|
||||
* @param length of data sent
|
||||
* @return ERR_OK if everything is ok, -1 otherwise
|
||||
*
|
||||
*/
|
||||
err_t nc_sent(void *arg, struct tcp_pcb *PCB, u16_t len);
|
||||
|
||||
/*
|
||||
* Callback from LWIP which sends a return value to the client to signal that
|
||||
* a connection was established for this PCB
|
||||
*
|
||||
* @param associated service state object
|
||||
* @param relevant PCB
|
||||
* @param error code
|
||||
* @return ERR_OK if everything is ok, -1 otherwise
|
||||
*
|
||||
*/
|
||||
err_t nc_connected(void *arg, struct tcp_pcb *PCB, err_t err);
|
||||
err_t nc_connected_proxy(void *arg, struct tcp_pcb *PCB, err_t err);
|
||||
}
|
||||
|
||||
#ifdef D_GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
struct tcp_pcb;
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
#define NETIF_ADD_SIG struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input
|
||||
#define ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr
|
||||
#endif
|
||||
|
||||
#if defined(SDK_IPV6)
|
||||
#define NETIF_ADD_SIG struct netif *netif, void *state, netif_init_fn init, netif_input_fn input
|
||||
#define ETHIP6_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr
|
||||
#define ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ipaddr
|
||||
#define NETIF_IP6_ADDR_SET_STATE_SIG struct netif* netif, s8_t addr_idx, u8_t state
|
||||
#define NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG struct netif *netif, u8_t from_mac_48bit
|
||||
#endif
|
||||
|
||||
// lwip General Stack API
|
||||
#define PBUF_FREE_SIG struct pbuf *p
|
||||
#define PBUF_ALLOC_SIG pbuf_layer layer, u16_t length, pbuf_type type
|
||||
#define LWIP_HTONS_SIG u16_t x
|
||||
#define LWIP_NTOHS_SIG u16_t x
|
||||
|
||||
// lwIP UDP API
|
||||
#define UDP_NEW_SIG void
|
||||
#define UDP_CONNECT_SIG struct udp_pcb * pcb, ip_addr_t * ipaddr, u16_t port
|
||||
#define UDP_SEND_SIG struct udp_pcb * pcb, struct pbuf * p
|
||||
#define UDP_SENDTO_SIG struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port
|
||||
#define UDP_RECV_SIG struct udp_pcb * pcb, void (* recv)(void * arg, struct udp_pcb * upcb, struct pbuf * p, ip_addr_t * addr, u16_t port), void * recv_arg
|
||||
#define UDP_RECVED_SIG struct udp_pcb * pcb, u16_t len
|
||||
#define UDP_BIND_SIG struct udp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port
|
||||
#define UDP_REMOVE_SIG struct udp_pcb *pcb
|
||||
|
||||
// lwIP TCP API
|
||||
#define TCP_WRITE_SIG struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags
|
||||
#define TCP_SENT_SIG struct tcp_pcb * pcb, err_t (* sent)(void * arg, struct tcp_pcb * tpcb, u16_t len)
|
||||
#define TCP_NEW_SIG void
|
||||
#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
|
||||
#define TCP_RECVED_SIG struct tcp_pcb * pcb, u16_t len
|
||||
#define TCP_SNDBUF_SIG struct tcp_pcb * pcb
|
||||
#define TCP_CONNECT_SIG struct tcp_pcb * pcb, ip_addr_t * ipaddr, u16_t port, err_t (* connected)(void * arg, struct tcp_pcb * tpcb, err_t err)
|
||||
#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
|
||||
#define TCP_ERR_SIG struct tcp_pcb * pcb, void (* err)(void * arg, err_t err)
|
||||
#define TCP_POLL_SIG struct tcp_pcb * pcb, err_t (* poll)(void * arg, struct tcp_pcb * tpcb), u8_t interval
|
||||
#define TCP_ARG_SIG struct tcp_pcb * pcb, void * arg
|
||||
#define TCP_CLOSE_SIG struct tcp_pcb * pcb
|
||||
#define TCP_ABORT_SIG struct tcp_pcb * pcb
|
||||
#define TCP_OUTPUT_SIG struct tcp_pcb * pcb
|
||||
#define TCP_ACCEPT_SIG struct tcp_pcb * pcb, err_t (* accept)(void * arg, struct tcp_pcb * newpcb, err_t err)
|
||||
#define TCP_LISTEN_SIG struct tcp_pcb * pcb
|
||||
#define TCP_LISTEN_WITH_BACKLOG_SIG struct tcp_pcb * pcb, u8_t backlog
|
||||
#define TCP_BIND_SIG struct tcp_pcb * pcb, const ip_addr_t * ipaddr, u16_t port
|
||||
#define TCP_INPUT_SIG struct pbuf *p, struct netif *inp
|
||||
|
||||
// lwIP network stack interfaces
|
||||
#define ETHERNET_INPUT_SIG struct pbuf *p, struct netif *netif
|
||||
#define IP_INPUT_SIG struct pbuf *p, struct netif *inp
|
||||
#define NETIF_SET_DEFAULT_SIG struct netif *netif
|
||||
#define NETIF_SET_UP_SIG struct netif *netif
|
||||
#define NETIF_POLL_SIG struct netif *netif
|
||||
|
||||
//#define NETIF_SET_ADDR_SIG struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Loads an instance of liblwip.so in a private memory arena
|
||||
*
|
||||
* This uses dlmopen() to load an instance of the LWIP stack into its
|
||||
* own private memory space. This is done to get around the stack's
|
||||
* lack of thread-safety or multi-instance support. The alternative
|
||||
* would be to massively refactor the stack so everything lives in a
|
||||
* state object instead of static memory space.
|
||||
*/
|
||||
class lwIP_stack
|
||||
{
|
||||
public:
|
||||
|
||||
void *_libref;
|
||||
|
||||
void close() {
|
||||
#if defined(__STATIC_STACK__)
|
||||
return;
|
||||
#elif defined(__DYNAMIC_STACK__)
|
||||
dlclose(_libref);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
err_t (*_etharp_output)(ETHARP_OUTPUT_SIG);
|
||||
#endif
|
||||
|
||||
#if defined(SDK_IPV6)
|
||||
err_t (*_ethip6_output)(ETHIP6_OUTPUT_SIG);
|
||||
void (*_nd6_tmr)(void);
|
||||
void (*_netif_ip6_addr_set_state)(NETIF_IP6_ADDR_SET_STATE_SIG);
|
||||
void (*_netif_create_ip6_linklocal_address)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG);
|
||||
#endif
|
||||
|
||||
void (*_netif_init)(void);
|
||||
// void (*_netif_set_addr)(NETIF_SET_ADDR_SIG);
|
||||
|
||||
void (*_lwip_init)();
|
||||
err_t (*_tcp_write)(TCP_WRITE_SIG);
|
||||
void (*_tcp_sent)(TCP_SENT_SIG);
|
||||
struct tcp_pcb * (*_tcp_new)(TCP_NEW_SIG);
|
||||
u16_t (*_tcp_sndbuf)(TCP_SNDBUF_SIG);
|
||||
err_t (*_tcp_connect)(TCP_CONNECT_SIG);
|
||||
struct udp_pcb * (*_udp_new)(UDP_NEW_SIG);
|
||||
err_t (*_udp_connect)(UDP_CONNECT_SIG);
|
||||
err_t (*_udp_send)(UDP_SEND_SIG);
|
||||
err_t (*_udp_sendto)(UDP_SENDTO_SIG);
|
||||
void (*_udp_recv)(UDP_RECV_SIG);
|
||||
void (*_udp_recved)(UDP_RECVED_SIG);
|
||||
err_t (*_udp_bind)(UDP_BIND_SIG);
|
||||
void (*_udp_remove)(UDP_REMOVE_SIG);
|
||||
void (*_tcp_recv)(TCP_RECV_SIG);
|
||||
void (*_tcp_recved)(TCP_RECVED_SIG);
|
||||
void (*_tcp_err)(TCP_ERR_SIG);
|
||||
void (*_tcp_poll)(TCP_POLL_SIG);
|
||||
void (*_tcp_arg)(TCP_ARG_SIG);
|
||||
err_t (*_tcp_close)(TCP_CLOSE_SIG);
|
||||
void (*_tcp_abort)(TCP_ABORT_SIG);
|
||||
err_t (*_tcp_output)(TCP_OUTPUT_SIG);
|
||||
void (*_tcp_accept)(TCP_ACCEPT_SIG);
|
||||
struct tcp_pcb * (*_tcp_listen)(TCP_LISTEN_SIG);
|
||||
struct tcp_pcb * (*_tcp_listen_with_backlog)(TCP_LISTEN_WITH_BACKLOG_SIG);
|
||||
err_t (*_tcp_bind)(TCP_BIND_SIG);
|
||||
void (*_etharp_tmr)(void);
|
||||
void (*_tcp_tmr)(void);
|
||||
u8_t (*_pbuf_free)(PBUF_FREE_SIG);
|
||||
struct pbuf * (*_pbuf_alloc)(PBUF_ALLOC_SIG);
|
||||
u16_t (*_lwip_htons)(LWIP_HTONS_SIG);
|
||||
u16_t (*_lwip_ntohs)(LWIP_NTOHS_SIG);
|
||||
err_t (*_ethernet_input)(ETHERNET_INPUT_SIG);
|
||||
void (*_tcp_input)(TCP_INPUT_SIG);
|
||||
err_t (*_ip_input)(IP_INPUT_SIG);
|
||||
void (*_netif_set_default)(NETIF_SET_DEFAULT_SIG);
|
||||
struct netif * (*_netif_add)(NETIF_ADD_SIG);
|
||||
void (*_netif_set_up)(NETIF_SET_UP_SIG);
|
||||
void (*_netif_poll)(NETIF_POLL_SIG);
|
||||
|
||||
Mutex _lock;
|
||||
Mutex _lock_mem;
|
||||
|
||||
lwIP_stack(const char* path) :
|
||||
_libref(NULL)
|
||||
{
|
||||
#if defined(__ANDROID__) || defined(__UNITY_3D__)
|
||||
#define __STATIC_STACK__
|
||||
#elif defined(__linux__)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load liblwip.so
|
||||
_libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW);
|
||||
#elif defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#include "node/Mutex.hpp"
|
||||
#define __STATIC_STACK__
|
||||
// iOS Simulator or iOS device
|
||||
// Do nothing, symbols are statically-linked
|
||||
#elif TARGET_OS_MAC && !defined(SDK_BUNDLED)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load liblwip.so
|
||||
_libref = dlopen(path, RTLD_NOW);
|
||||
#elif TARGET_OS_MAC && defined(SDK_BUNDLED)
|
||||
#define __DYNAMIC_STACK__ // TODO: Implement static version
|
||||
// Dynamically load liblwip.so
|
||||
_libref = dlopen(path, RTLD_NOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __STATIC_STACK__ // Set static references (for use in iOS)
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
_etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))ðarp_output;
|
||||
#endif
|
||||
|
||||
#if defined(SDK_IPV6)
|
||||
_nd6_tmr = (void(*)(void))&nd6_tmr;
|
||||
_netif_ip6_addr_set_state = (void(*)(NETIF_IP6_ADDR_SET_STATE_SIG))&netif_ip6_addr_set_state;
|
||||
_netif_create_ip6_linklocal_address = (void(*)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG))&netif_create_ip6_linklocal_address;
|
||||
_ethip6_output = (err_t(*)(ETHIP6_OUTPUT_SIG))ðip6_output;
|
||||
#endif
|
||||
|
||||
_netif_init = (void(*)(void))&netif_init;
|
||||
_ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))ðernet_input;
|
||||
_lwip_init = (void(*)(void))&lwip_init;
|
||||
_tcp_write = (err_t(*)(TCP_WRITE_SIG))&tcp_write;
|
||||
_tcp_sent = (void(*)(TCP_SENT_SIG))&tcp_sent;
|
||||
_tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))&tcp_new;
|
||||
_udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))&udp_new;
|
||||
_udp_connect = (err_t(*)(UDP_CONNECT_SIG))&udp_connect;
|
||||
_udp_send = (err_t(*)(UDP_SEND_SIG))&udp_send;
|
||||
_udp_sendto = (err_t(*)(UDP_SENDTO_SIG))&udp_sendto;
|
||||
_udp_recv = (void(*)(UDP_RECV_SIG))&udp_recv;
|
||||
_udp_bind = (err_t(*)(UDP_BIND_SIG))&udp_bind;
|
||||
_udp_remove = (void(*)(UDP_REMOVE_SIG))&udp_remove;
|
||||
_tcp_connect = (err_t(*)(TCP_CONNECT_SIG))&tcp_connect;
|
||||
_tcp_recv = (void(*)(TCP_RECV_SIG))&tcp_recv;
|
||||
_tcp_recved = (void(*)(TCP_RECVED_SIG))&tcp_recved;
|
||||
_tcp_err = (void(*)(TCP_ERR_SIG))&tcp_err;
|
||||
_tcp_poll = (void(*)(TCP_POLL_SIG))&tcp_poll;
|
||||
_tcp_arg = (void(*)(TCP_ARG_SIG))&tcp_arg;
|
||||
_tcp_close = (err_t(*)(TCP_CLOSE_SIG))&tcp_close;
|
||||
_tcp_abort = (void(*)(TCP_ABORT_SIG))&tcp_abort;
|
||||
_tcp_output = (err_t(*)(TCP_OUTPUT_SIG))&tcp_output;
|
||||
_tcp_accept = (void(*)(TCP_ACCEPT_SIG))&tcp_accept;
|
||||
_tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))&tcp_listen_with_backlog;
|
||||
_tcp_bind = (err_t(*)(TCP_BIND_SIG))&tcp_bind;
|
||||
_etharp_tmr = (void(*)(void))ðarp_tmr;
|
||||
_tcp_tmr = (void(*)(void))&tcp_tmr;
|
||||
_pbuf_free = (u8_t(*)(PBUF_FREE_SIG))&pbuf_free;
|
||||
_pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))&pbuf_alloc;
|
||||
_lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))&lwip_htons;
|
||||
_lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))&lwip_ntohs;
|
||||
_tcp_input = (void(*)(TCP_INPUT_SIG))&tcp_input;
|
||||
_ip_input = (err_t(*)(IP_INPUT_SIG))&ip_input;
|
||||
_netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))&netif_set_default;
|
||||
_netif_add = (struct netif*(*)(NETIF_ADD_SIG))&netif_add;
|
||||
_netif_set_up = (void(*)(NETIF_SET_UP_SIG))&netif_set_up;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications)
|
||||
|
||||
if(_libref == NULL)
|
||||
DEBUG_ERROR("dlerror(): %s", dlerror());
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
_etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))dlsym(_libref, "etharp_output");
|
||||
#endif
|
||||
|
||||
#if defined(SDK_IPV6)
|
||||
_nd6_tmr = (void(*)(void))dlsym(_libref, "nd6_tmr");
|
||||
_netif_ip6_addr_set_state = (void(*)(NETIF_IP6_ADDR_SET_STATE_SIG))dlsym(_libref, "netif_ip6_addr_set_state");
|
||||
_netif_create_ip6_linklocal_address = (void(*)(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG))dlsym(_libref, "netif_create_ip6_linklocal_address");
|
||||
_ethip6_output = (err_t(*)(ETHIP6_OUTPUT_SIG))dlsym(_libref, "ethip6_output");
|
||||
#endif
|
||||
|
||||
_netif_init = (void(*)(void))dlsym(_libref, "netif_init");
|
||||
// _netif_set_addr = (void(*))(NETIF_SET_ADDR_SIG))dlsym(_libref, "netif_set_addr");
|
||||
|
||||
_ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))dlsym(_libref, "ethernet_input");
|
||||
_lwip_init = (void(*)(void))dlsym(_libref, "lwip_init");
|
||||
_tcp_write = (err_t(*)(TCP_WRITE_SIG))dlsym(_libref, "tcp_write");
|
||||
_tcp_sent = (void(*)(TCP_SENT_SIG))dlsym(_libref, "tcp_sent");
|
||||
_tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))dlsym(_libref, "tcp_new");
|
||||
_udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))dlsym(_libref, "udp_new");
|
||||
_udp_connect = (err_t(*)(UDP_CONNECT_SIG))dlsym(_libref, "udp_connect");
|
||||
_udp_send = (err_t(*)(UDP_SEND_SIG))dlsym(_libref, "udp_send");
|
||||
_udp_sendto = (err_t(*)(UDP_SENDTO_SIG))dlsym(_libref, "udp_sendto");
|
||||
_udp_recv = (void(*)(UDP_RECV_SIG))dlsym(_libref, "udp_recv");
|
||||
_udp_bind = (err_t(*)(UDP_BIND_SIG))dlsym(_libref, "udp_bind");
|
||||
_udp_remove = (void(*)(UDP_REMOVE_SIG))dlsym(_libref, "udp_remove");
|
||||
_tcp_sndbuf = (u16_t(*)(TCP_SNDBUF_SIG))dlsym(_libref, "tcp_sndbuf");
|
||||
_tcp_connect = (err_t(*)(TCP_CONNECT_SIG))dlsym(_libref, "tcp_connect");
|
||||
_tcp_recv = (void(*)(TCP_RECV_SIG))dlsym(_libref, "tcp_recv");
|
||||
_tcp_recved = (void(*)(TCP_RECVED_SIG))dlsym(_libref, "tcp_recved");
|
||||
_tcp_err = (void(*)(TCP_ERR_SIG))dlsym(_libref, "tcp_err");
|
||||
_tcp_poll = (void(*)(TCP_POLL_SIG))dlsym(_libref, "tcp_poll");
|
||||
_tcp_arg = (void(*)(TCP_ARG_SIG))dlsym(_libref, "tcp_arg");
|
||||
_tcp_close = (err_t(*)(TCP_CLOSE_SIG))dlsym(_libref, "tcp_close");
|
||||
_tcp_abort = (void(*)(TCP_ABORT_SIG))dlsym(_libref, "tcp_abort");
|
||||
_tcp_output = (err_t(*)(TCP_OUTPUT_SIG))dlsym(_libref, "tcp_output");
|
||||
_tcp_accept = (void(*)(TCP_ACCEPT_SIG))dlsym(_libref, "tcp_accept");
|
||||
_tcp_listen = (struct tcp_pcb*(*)(TCP_LISTEN_SIG))dlsym(_libref, "tcp_listen");
|
||||
_tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))dlsym(_libref, "tcp_listen_with_backlog");
|
||||
_tcp_bind = (err_t(*)(TCP_BIND_SIG))dlsym(_libref, "tcp_bind");
|
||||
_etharp_tmr = (void(*)(void))dlsym(_libref, "etharp_tmr");
|
||||
_tcp_tmr = (void(*)(void))dlsym(_libref, "tcp_tmr");
|
||||
_pbuf_free = (u8_t(*)(PBUF_FREE_SIG))dlsym(_libref, "pbuf_free");
|
||||
_pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))dlsym(_libref, "pbuf_alloc");
|
||||
_lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))dlsym(_libref, "lwip_htons");
|
||||
_lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))dlsym(_libref, "lwip_ntohs");
|
||||
_tcp_input = (void(*)(TCP_INPUT_SIG))dlsym(_libref, "tcp_input");
|
||||
_ip_input = (err_t(*)(IP_INPUT_SIG))dlsym(_libref, "ip_input");
|
||||
_netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))dlsym(_libref, "netif_set_default");
|
||||
_netif_add = (struct netif*(*)(NETIF_ADD_SIG))dlsym(_libref, "netif_add");
|
||||
_netif_set_up = (void(*)(NETIF_SET_UP_SIG))dlsym(_libref, "netif_set_up");
|
||||
#endif
|
||||
}
|
||||
|
||||
~lwIP_stack()
|
||||
{
|
||||
if (_libref)
|
||||
dlclose(_libref);
|
||||
}
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
inline struct netif * __netif_add(NETIF_ADD_SIG) throw() { Mutex::Lock _l(_lock); return _netif_add(netif,ipaddr,netmask,gw,state,init,input); }
|
||||
#endif
|
||||
|
||||
#if defined(SDK_IPV6)
|
||||
inline struct netif * __netif_add(NETIF_ADD_SIG) throw() { Mutex::Lock _l(_lock); return _netif_add(netif,state,init,input); }
|
||||
inline void __nd6_tmr(void) throw() { /**/ Mutex::Lock _l(_lock); _nd6_tmr(); }
|
||||
inline void __netif_ip6_addr_set_state(NETIF_IP6_ADDR_SET_STATE_SIG) throw() { Mutex::Lock _l(_lock); _netif_ip6_addr_set_state(netif, addr_idx, state); }
|
||||
inline void __netif_create_ip6_linklocal_address(NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG) throw() { Mutex::Lock _l(_lock); _netif_create_ip6_linklocal_address(netif, from_mac_48bit); }
|
||||
inline err_t __ethip6_output(ETHIP6_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ethip6_output(netif,q,ip6addr); }
|
||||
#endif
|
||||
|
||||
inline void __netif_init(void) throw() { Mutex::Lock _l(_lock); _netif_init(); }
|
||||
// inline void __netif_set_addr(NETIF_SET_ADDR_SIG) throw() { Mutex::Lock _l(_lock); _netif_set_addr(netif, ipaddr, netmask, gw); }
|
||||
inline void __lwip_init() throw() { Mutex::Lock _l(_lock); return _lwip_init(); }
|
||||
inline err_t __tcp_write(TCP_WRITE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_write(pcb,arg,len,apiflags); }
|
||||
inline void __tcp_sent(TCP_SENT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sent(pcb,sent); }
|
||||
inline struct tcp_pcb * __tcp_new(TCP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_new(); }
|
||||
inline struct udp_pcb * __udp_new(UDP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _udp_new(); }
|
||||
inline err_t __udp_connect(UDP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _udp_connect(pcb,ipaddr,port); }
|
||||
inline err_t __udp_send(UDP_SEND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_send(pcb,p); }
|
||||
inline err_t __udp_sendto(UDP_SENDTO_SIG) throw() { Mutex::Lock _l(_lock); return _udp_sendto(pcb,p,dst_ip,dst_port); }
|
||||
inline void __udp_recv(UDP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _udp_recv(pcb,recv,recv_arg); }
|
||||
inline err_t __udp_bind(UDP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_bind(pcb,ipaddr,port); }
|
||||
inline void __udp_remove(UDP_REMOVE_SIG) throw() { Mutex::Lock _l(_lock); return _udp_remove(pcb); }
|
||||
inline u16_t __tcp_sndbuf(TCP_SNDBUF_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sndbuf(pcb); }
|
||||
inline err_t __tcp_connect(TCP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_connect(pcb,ipaddr,port,connected); }
|
||||
inline void __tcp_recv(TCP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recv(pcb,recv); }
|
||||
inline void __tcp_recved(TCP_RECVED_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recved(pcb,len); }
|
||||
inline void __tcp_err(TCP_ERR_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_err(pcb,err); }
|
||||
inline void __tcp_poll(TCP_POLL_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_poll(pcb,poll,interval); }
|
||||
inline void __tcp_arg(TCP_ARG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_arg(pcb,arg); }
|
||||
inline err_t __tcp_close(TCP_CLOSE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_close(pcb); }
|
||||
inline void __tcp_abort(TCP_ABORT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_abort(pcb); }
|
||||
inline err_t __tcp_output(TCP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_output(pcb); }
|
||||
inline void __tcp_accept(TCP_ACCEPT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_accept(pcb,accept); }
|
||||
inline struct tcp_pcb * __tcp_listen(TCP_LISTEN_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen(pcb); }
|
||||
inline struct tcp_pcb * __tcp_listen_with_backlog(TCP_LISTEN_WITH_BACKLOG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen_with_backlog(pcb,backlog); }
|
||||
inline err_t __tcp_bind(TCP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_bind(pcb,ipaddr,port); }
|
||||
inline void __etharp_tmr(void) throw() { Mutex::Lock _l(_lock); return _etharp_tmr(); }
|
||||
inline void __tcp_tmr(void) throw() { Mutex::Lock _l(_lock); return _tcp_tmr(); }
|
||||
inline u8_t __pbuf_free(PBUF_FREE_SIG) throw() { Mutex::Lock _l(_lock); return _pbuf_free(p); }
|
||||
inline struct pbuf * __pbuf_alloc(PBUF_ALLOC_SIG) throw() { Mutex::Lock _l(_lock_mem); return _pbuf_alloc(layer,length,type); }
|
||||
inline u16_t __lwip_htons(LWIP_HTONS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_htons(x); }
|
||||
inline u16_t __lwip_ntohs(LWIP_NTOHS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_ntohs(x); }
|
||||
//inline err_t __etharp_output(ETHARP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _etharp_output(netif,q,ipaddr); }
|
||||
inline err_t __ethernet_input(ETHERNET_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ethernet_input(p,netif); }
|
||||
inline void __tcp_input(TCP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_input(p,inp); }
|
||||
inline err_t __ip_input(IP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ip_input(p,inp); }
|
||||
inline void __netif_set_default(NETIF_SET_DEFAULT_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_default(netif); }
|
||||
inline void __netif_set_up(NETIF_SET_UP_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_up(netif); }
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDK_LWIP
|
||||
@@ -1,496 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* lwIP Options Configuration
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_H__
|
||||
|
||||
/*
|
||||
* Include user defined options first. Anything not defined in these files
|
||||
* will be set to standard values. Override anything you dont like!
|
||||
*/
|
||||
#include "lwip/debug.h"
|
||||
|
||||
// IP Protocol version
|
||||
// It seems using ipv6/ipv4 in the same stack is problematic, for this reason we
|
||||
// compile for only one or the other using the SDK_IPV4=1/SDK_IPV6=1 flags for now
|
||||
#if defined(SDK_IPV6)
|
||||
#define LWIP_IPV6 1
|
||||
#define LWIP_IPV4 0
|
||||
|
||||
#endif
|
||||
#if defined(SDK_IPV4)
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_IPV6 0
|
||||
#endif
|
||||
|
||||
#define LWIP_TCP 1
|
||||
#define IP6_DEBUG 1
|
||||
#define LWIP_DEBUG 1
|
||||
#define IP_DEBUG LWIP_DBG_ON
|
||||
#define LWIP_ETHERNET 1
|
||||
|
||||
#define LWIP_DBG_TYPES_ON LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_FRESH
|
||||
|
||||
#define LWIP_CHKSUM_ALGORITHM 2
|
||||
|
||||
#undef TCP_MSS
|
||||
#define TCP_MSS 1460
|
||||
|
||||
/*
|
||||
The TCP window size can be adjusted by changing the define TCP_WND. However,
|
||||
do keep in mind that this should be at least twice the size of TCP_MSS (thus
|
||||
on ethernet, where TCP_MSS is 1460, it should be set to at least 2920). If
|
||||
memory allows it, set this as high as possible (16-bit, so 0xFFFF is the highest
|
||||
value), but keep in mind that for every active connection, the full window may
|
||||
have to be buffered until it is acknowledged by the remote side (although this
|
||||
buffer size can still be controlled by TCP_SND_BUF and TCP_SND_QUEUELEN). The
|
||||
reason for "twice" are both the nagle algorithm and delayed ACK from the
|
||||
remote peer.
|
||||
*/
|
||||
|
||||
#define TCP_WND TCP_MSS*10 // max = 0xffff
|
||||
|
||||
//#define LWIP_NOASSERT 1
|
||||
#define TCP_LISTEN_BACKLOG 0
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
---------------------------------- Timers --------------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Be careful about setting this too small. lwIP just counts the number
|
||||
of times its timer is called and uses this to control time sensitive
|
||||
operations (such as TCP retransmissions), rather than actually
|
||||
measuring time using something more accurate. If you call the timer
|
||||
functions very frequently you may see things (such as retransmissions)
|
||||
happening sooner than they should.
|
||||
*/
|
||||
/* these are originally defined in tcp_impl.h */
|
||||
#ifndef TCP_TMR_INTERVAL
|
||||
/* The TCP timer interval in milliseconds. */
|
||||
#define TCP_TMR_INTERVAL 250
|
||||
#endif /* TCP_TMR_INTERVAL */
|
||||
|
||||
#ifndef TCP_FAST_INTERVAL
|
||||
/* the fine grained timeout in milliseconds */
|
||||
#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL
|
||||
#endif /* TCP_FAST_INTERVAL */
|
||||
|
||||
#ifndef TCP_SLOW_INTERVALs
|
||||
/* the coarse grained timeout in milliseconds */
|
||||
#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL)
|
||||
#endif /* TCP_SLOW_INTERVAL */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
--------------------------- Platform specific locking -------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
|
||||
* critical regions during buffer allocation, deallocation and memory
|
||||
* allocation and deallocation.
|
||||
*/
|
||||
#define SYS_LIGHTWEIGHT_PROT 0
|
||||
|
||||
/**
|
||||
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
|
||||
* use lwIP facilities.
|
||||
*/
|
||||
|
||||
/* set to 1 so we have no thread behaviour */
|
||||
#define NO_SYS 1
|
||||
|
||||
/* set to 1 so we can use our own timers */
|
||||
#define NO_SYS_NO_TIMERS 1
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- Memory options --------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/* Misc */
|
||||
#define MEM_LIBC_MALLOC 1
|
||||
#define MEMP_MEM_MALLOC 1
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MEM_ALIGNMENT: should be set to the alignment of the CPU
|
||||
* 4 byte alignment -> #define MEM_ALIGNMENT 4
|
||||
* 2 byte alignment -> #define MEM_ALIGNMENT 2
|
||||
*/
|
||||
#define MEM_ALIGNMENT 1
|
||||
|
||||
/**
|
||||
* MEM_SIZE: the size of the heap memory. If the application will send
|
||||
* a lot of data that needs to be copied, this should be set high.
|
||||
*/
|
||||
#define MEM_SIZE 1024 * 1024 * 64
|
||||
#define TCP_SND_BUF 1024 * 63
|
||||
//#define TCP_OVERSIZE TCP_MSS
|
||||
|
||||
#define TCP_SND_QUEUELEN 1024
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- Pbuf Options ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
|
||||
* link level header. The default is 14, the standard value for
|
||||
* Ethernet.
|
||||
*/
|
||||
#define PBUF_LINK_HLEN 16
|
||||
|
||||
/**
|
||||
* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is
|
||||
* designed to accomodate single full size TCP frame in one pbuf, including
|
||||
* TCP_MSS, IP header, and link header.
|
||||
*
|
||||
*/
|
||||
#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------- Internal Memory Pool Sizes --------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).
|
||||
* If the application sends a lot of data out of ROM (or other static memory),
|
||||
* this should be set high.
|
||||
*/
|
||||
#define MEMP_NUM_PBUF 256
|
||||
|
||||
/**
|
||||
* MEMP_NUM_RAW_PCB: Number of raw connection PCBs
|
||||
* (requires the LWIP_RAW option)
|
||||
*/
|
||||
#define MEMP_NUM_RAW_PCB 128
|
||||
|
||||
/**
|
||||
* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
|
||||
* per active UDP "connection".
|
||||
* (requires the LWIP_UDP option)
|
||||
*/
|
||||
#define MEMP_NUM_UDP_PCB 4
|
||||
|
||||
/**
|
||||
* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.
|
||||
* (requires the LWIP_TCP option)
|
||||
*/
|
||||
#define MEMP_NUM_TCP_PCB 128
|
||||
|
||||
/**
|
||||
* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.
|
||||
* (requires the LWIP_TCP option)
|
||||
*/
|
||||
#define MEMP_NUM_TCP_PCB_LISTEN 128
|
||||
|
||||
/**
|
||||
* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.
|
||||
* (requires the LWIP_TCP option)
|
||||
*/
|
||||
#define MEMP_NUM_TCP_SEG 1024
|
||||
|
||||
/**
|
||||
* MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for
|
||||
* reassembly (whole packets, not fragments!)
|
||||
*/
|
||||
#define MEMP_NUM_REASSDATA 1
|
||||
|
||||
/**
|
||||
* MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
|
||||
* packets (pbufs) that are waiting for an ARP request (to resolve
|
||||
* their destination address) to finish.
|
||||
* (requires the ARP_QUEUEING option)
|
||||
*/
|
||||
#define MEMP_NUM_ARP_QUEUE 2
|
||||
|
||||
/**
|
||||
* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
|
||||
* (requires NO_SYS==0)
|
||||
*/
|
||||
#define MEMP_NUM_SYS_TIMEOUT 3
|
||||
|
||||
/**
|
||||
* MEMP_NUM_NETBUF: the number of struct netbufs.
|
||||
* (only needed if you use the sequential API, like api_lib.c)
|
||||
*/
|
||||
#define MEMP_NUM_NETBUF 2
|
||||
|
||||
/**
|
||||
* MEMP_NUM_NETCONN: the number of struct netconns.
|
||||
* (only needed if you use the sequential API, like api_lib.c)
|
||||
*/
|
||||
#define MEMP_NUM_NETCONN 4
|
||||
|
||||
/**
|
||||
* MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used
|
||||
* for callback/timeout API communication.
|
||||
* (only needed if you use tcpip.c)
|
||||
*/
|
||||
#define MEMP_NUM_TCPIP_MSG_API 8
|
||||
|
||||
/**
|
||||
* MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used
|
||||
* for incoming packets.
|
||||
* (only needed if you use tcpip.c)
|
||||
*/
|
||||
#define MEMP_NUM_TCPIP_MSG_INPKT 8
|
||||
|
||||
/**
|
||||
* PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
|
||||
*/
|
||||
#define PBUF_POOL_SIZE 2048 /* was 32 */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
----------------------------------- ARP options --------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_ARP==1: Enable ARP functionality.
|
||||
*/
|
||||
#define LWIP_ARP 1
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------------ IP options---------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* IP_FORWARD==1: Enables the ability to forward IP packets across network
|
||||
* interfaces. If you are going to run lwIP on a device with only one network
|
||||
* interface, define this to 0.
|
||||
*/
|
||||
#define IP_FORWARD 0
|
||||
|
||||
/**
|
||||
* IP_OPTIONS: Defines the behavior for IP options.
|
||||
* IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.
|
||||
* IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).
|
||||
*/
|
||||
#define IP_OPTIONS_ALLOWED 1
|
||||
|
||||
/**
|
||||
* IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that
|
||||
* this option does not affect outgoing packet sizes, which can be controlled
|
||||
* via IP_FRAG.
|
||||
*/
|
||||
#define IP_REASSEMBLY 1
|
||||
|
||||
/**
|
||||
* IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note
|
||||
* that this option does not affect incoming packet sizes, which can be
|
||||
* controlled via IP_REASSEMBLY.
|
||||
*/
|
||||
#define IP_FRAG 1
|
||||
|
||||
/**
|
||||
* IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)
|
||||
* a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived
|
||||
* in this time, the whole packet is discarded.
|
||||
*/
|
||||
#define IP_REASS_MAXAGE 3
|
||||
|
||||
/**
|
||||
* IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.
|
||||
* Since the received pbufs are enqueued, be sure to configure
|
||||
* PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive
|
||||
* packets even if the maximum amount of fragments is enqueued for reassembly!
|
||||
*/
|
||||
#define IP_REASS_MAX_PBUFS 4
|
||||
|
||||
/**
|
||||
* IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP
|
||||
* fragmentation. Otherwise pbufs are allocated and reference the original
|
||||
* packet data to be fragmented.
|
||||
*/
|
||||
#define IP_FRAG_USES_STATIC_BUF 0
|
||||
|
||||
/**
|
||||
* IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.
|
||||
*/
|
||||
#define IP_DEFAULT_TTL 255
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------- ICMP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_ICMP==1: Enable ICMP module inside the IP stack.
|
||||
* Be careful, disable that make your product non-compliant to RFC1122
|
||||
*/
|
||||
#define LWIP_ICMP 1
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------- RAW Options ------------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
|
||||
*/
|
||||
#define LWIP_RAW 1
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------- DHCP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_DHCP==1: Enable DHCP module.
|
||||
*/
|
||||
#define LWIP_DHCP 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------ AUTOIP Options ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_AUTOIP==1: Enable AUTOIP module.
|
||||
*/
|
||||
#define LWIP_AUTOIP 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------- SNMP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP
|
||||
* transport.
|
||||
*/
|
||||
#define LWIP_SNMP 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------- IGMP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_IGMP==1: Turn on IGMP module.
|
||||
*/
|
||||
#define LWIP_IGMP 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- DNS Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS
|
||||
* transport.
|
||||
*/
|
||||
#define LWIP_DNS 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- UDP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_UDP==1: Turn on UDP.
|
||||
*/
|
||||
#define LWIP_UDP 1
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- TCP Options -----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_TCP==1: Turn on TCP.
|
||||
*/
|
||||
#define LWIP_TCP 1
|
||||
|
||||
#define LWIP_LISTEN_BACKLOG 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
--------------------------------- LOOPIF Options -------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c
|
||||
*/
|
||||
#define LWIP_HAVE_LOOPIF 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
---------------------------- Sequential Layer Options --------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
|
||||
*/
|
||||
#define LWIP_NETCONN 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
--------------------------------- Socket Options -------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
|
||||
*/
|
||||
#define LWIP_SOCKET 0
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------ Statistics Options ------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* LWIP_STATS==1: Enable statistics collection in lwip_stats.
|
||||
*/
|
||||
#define LWIP_STATS 0
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
--------------------------------- PPP Options ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* PPP_SUPPORT==1: Enable PPP.
|
||||
*/
|
||||
#define PPP_SUPPORT 0
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
@@ -1,2 +0,0 @@
|
||||
picoTCP Network Stack Driver
|
||||
====
|
||||
@@ -1,767 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#if defined(SDK_PICOTCP)
|
||||
|
||||
#include "tap.hpp"
|
||||
|
||||
#include "picotcp.hpp"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_icmp4.h"
|
||||
#include "pico_dev_tap.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_eth.h"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
// Reference to the tap interface
|
||||
// This is needed due to the fact that there's a lot going on in the tap interface
|
||||
// that needs to be updated on each of the network stack's callbacks and not every
|
||||
// network stack provides a mechanism for storing a reference to the tap.
|
||||
//
|
||||
// In future releases this will be replaced with a new structure of static pointers that
|
||||
// will make it easier to maintain multiple active tap interfaces
|
||||
NetconEthernetTap *picotap;
|
||||
struct pico_device picodev;
|
||||
|
||||
int pico_eth_send(struct pico_device *dev, void *buf, int len);
|
||||
int pico_eth_poll(struct pico_device *dev, int loop_score);
|
||||
|
||||
// Initialize network stack's interfaces and assign addresses
|
||||
void pico_init_interface(NetconEthernetTap *tap, const InetAddress &ip)
|
||||
{
|
||||
picoTCP_stack *stack = tap->picostack;
|
||||
if (std::find(picotap->_ips.begin(),picotap->_ips.end(),ip) == picotap->_ips.end()) {
|
||||
picotap->_ips.push_back(ip);
|
||||
std::sort(picotap->_ips.begin(),picotap->_ips.end());
|
||||
#if defined(SDK_IPV4)
|
||||
if(ip.isV4())
|
||||
{
|
||||
struct pico_ip4 ipaddr, netmask;
|
||||
ipaddr.addr = *((uint32_t *)ip.rawIpData());
|
||||
netmask.addr = *((uint32_t *)ip.netmask().rawIpData());
|
||||
uint8_t mac[PICO_SIZE_ETH];
|
||||
picotap->_mac.copyTo(mac, PICO_SIZE_ETH);
|
||||
DEBUG_ATTN("mac = %s", picotap->_mac.toString().c_str());
|
||||
picodev.send = pico_eth_send; // tx
|
||||
picodev.poll = pico_eth_poll; // rx
|
||||
picodev.mtu = picotap->_mtu;
|
||||
if( 0 != stack->__pico_device_init(&(picodev), "p0", mac)) {
|
||||
DEBUG_ERROR("device init failed");
|
||||
return;
|
||||
}
|
||||
stack->__pico_ipv4_link_add(&(picodev), ipaddr, netmask);
|
||||
// DEBUG_INFO("device initialized as ipv4_addr = %s", ipv4_str);
|
||||
// picostack->__pico_icmp4_ping("10.8.8.1", 20, 1000, 10000, 64, cb_ping);
|
||||
}
|
||||
#elif defined(SDK_IPV6)
|
||||
if(ip.isV6())
|
||||
{
|
||||
struct pico_ip6 ipaddr, netmask;
|
||||
char ipv6_str[INET6_ADDRSTRLEN], nm_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, ip.rawIpData(), ipv6_str, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, ip.netmask().rawIpData(), nm_str, INET6_ADDRSTRLEN);
|
||||
stack->__pico_string_to_ipv6(ipv6_str, ipaddr.addr);
|
||||
stack->__pico_string_to_ipv6(nm_str, netmask.addr);
|
||||
stack->__pico_ipv6_link_add(&(picodev), ipaddr, netmask);
|
||||
picodev.send = pico_eth_send; // tx
|
||||
picodev.poll = pico_eth_poll; // rx
|
||||
uint8_t mac[PICO_SIZE_ETH];
|
||||
picotap->_mac.copyTo(mac, PICO_SIZE_ETH);
|
||||
DEBUG_ATTN("mac = %s", picotap->_mac.toString().c_str());
|
||||
if( 0 != stack->__pico_device_init(&(picodev), "p0", mac)) {
|
||||
DEBUG_ERROR("device init failed");
|
||||
return;
|
||||
}
|
||||
DEBUG_ATTN("device initialized as ipv6_addr = %s", ipv6_str);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Main stack loop
|
||||
void pico_loop(NetconEthernetTap *tap)
|
||||
{
|
||||
while(tap->_run)
|
||||
{
|
||||
tap->_phy.poll(ZT_PHY_POLL_INTERVAL); // in ms
|
||||
tap->picostack->__pico_stack_tick();
|
||||
}
|
||||
}
|
||||
|
||||
// RX packets from [ZT->STACK] onto RXBUF
|
||||
// Also notify the tap service that data can be read:
|
||||
// [RXBUF -> (ZTSOCK->APP)]
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |<-----------------| | RX
|
||||
// -----------------------------------------
|
||||
// After this step, buffer will be emptied periodically by pico_handleRead()
|
||||
void pico_cb_tcp_read(NetconEthernetTap *tap, struct pico_socket *s)
|
||||
{
|
||||
Connection *conn = tap->getConnection(s);
|
||||
if(conn) {
|
||||
int r;
|
||||
uint16_t port = 0;
|
||||
union {
|
||||
struct pico_ip4 ip4;
|
||||
struct pico_ip6 ip6;
|
||||
} peer;
|
||||
|
||||
do {
|
||||
int avail = DEFAULT_TCP_RX_BUF_SZ - conn->rxsz;
|
||||
if(avail) {
|
||||
r = tap->picostack->__pico_socket_recvfrom(s, conn->rxbuf + (conn->rxsz), SDK_MTU, (void *)&peer.ip4.addr, &port);
|
||||
// DEBUG_ATTN("received packet (%d byte) from %08X:%u", r, long_be2(peer.ip4.addr), short_be(port));
|
||||
tap->_phy.setNotifyWritable(conn->sock, true);
|
||||
if (r > 0)
|
||||
conn->rxsz += r;
|
||||
}
|
||||
else
|
||||
DEBUG_ERROR("not enough space left on I/O RX buffer for pico_socket(%p)", s);
|
||||
}
|
||||
while(r > 0);
|
||||
return;
|
||||
}
|
||||
DEBUG_ERROR("invalid connection");
|
||||
}
|
||||
|
||||
// RX packets from the stack onto internal buffer
|
||||
// Also notifies the tap service that data can be read
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |<-----------------| | RX
|
||||
// -----------------------------------------
|
||||
// After this step, buffer will be emptied periodically by pico_handleRead()
|
||||
// Read payload is encapsulated as such:
|
||||
//
|
||||
// [addr|payload_len|payload]
|
||||
//
|
||||
void pico_cb_udp_read(NetconEthernetTap *tap, struct pico_socket *s)
|
||||
{
|
||||
Connection *conn = tap->getConnection(s);
|
||||
if(conn) {
|
||||
|
||||
uint16_t port = 0;
|
||||
union {
|
||||
struct pico_ip4 ip4;
|
||||
struct pico_ip6 ip6;
|
||||
} peer;
|
||||
|
||||
char tmpbuf[SDK_MTU];
|
||||
unsigned char *addr_pos, *sz_pos, *payload_pos;
|
||||
struct sockaddr_in addr_in;
|
||||
addr_in.sin_addr.s_addr = peer.ip4.addr;
|
||||
addr_in.sin_port = port;
|
||||
|
||||
// RX
|
||||
int r = tap->picostack->__pico_socket_recvfrom(s, tmpbuf, SDK_MTU, (void *)&peer.ip4.addr, &port);
|
||||
//DEBUG_FLOW(" [ RXBUF <- STACK] Receiving (%d) from stack, copying to receving buffer", r);
|
||||
|
||||
// Mutex::Lock _l2(tap->_rx_buf_m);
|
||||
// struct sockaddr_in6 addr_in6;
|
||||
// addr_in6.sin6_addr.s6_addr;
|
||||
// addr_in6.sin6_port = Utils::ntoh(s->remote_port);
|
||||
// DEBUG_ATTN("remote_port=%d, local_port=%d", s->remote_port, Utils::ntoh(s->local_port));
|
||||
picotap->_rx_buf_m.lock();
|
||||
if(conn->rxsz == DEFAULT_UDP_RX_BUF_SZ) { // if UDP buffer full
|
||||
//DEBUG_FLOW(" [ RXBUF <- STACK] UDP RX buffer full. Discarding oldest payload segment");
|
||||
memmove(conn->rxbuf, conn->rxbuf + SDK_MTU, DEFAULT_UDP_RX_BUF_SZ - SDK_MTU);
|
||||
addr_pos = conn->rxbuf + (DEFAULT_UDP_RX_BUF_SZ - SDK_MTU); // TODO:
|
||||
sz_pos = addr_pos + sizeof(struct sockaddr_storage);
|
||||
conn->rxsz -= SDK_MTU;
|
||||
}
|
||||
else {
|
||||
addr_pos = conn->rxbuf + conn->rxsz; // where we'll prepend the size of the address
|
||||
sz_pos = addr_pos + sizeof(struct sockaddr_storage);
|
||||
}
|
||||
payload_pos = addr_pos + sizeof(struct sockaddr_storage) + sizeof(r);
|
||||
memcpy(addr_pos, &addr_in, sizeof(struct sockaddr_storage));
|
||||
|
||||
memcpy(payload_pos, tmpbuf, r); // write payload to app's socket
|
||||
|
||||
// Adjust buffer size
|
||||
if(r) {
|
||||
conn->rxsz += SDK_MTU;
|
||||
memcpy(sz_pos, &r, sizeof(r));
|
||||
}
|
||||
if (r < 0) {
|
||||
DEBUG_ERROR("unable to read from picosock=%p", s);
|
||||
}
|
||||
picotap->_rx_buf_m.unlock();
|
||||
|
||||
// TODO: Revisit logic
|
||||
if(r)
|
||||
tap->phyOnUnixWritable(conn->sock, NULL, true);
|
||||
//DEBUG_EXTRA(" Copied onto rxbuf (%d) from stack socket", r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TX packets from internal buffer to network
|
||||
void pico_cb_tcp_write(NetconEthernetTap *tap, struct pico_socket *s)
|
||||
{
|
||||
Connection *conn = tap->getConnection(s);
|
||||
if(!conn)
|
||||
DEBUG_ERROR("invalid connection");
|
||||
if(!conn->txsz)
|
||||
return;
|
||||
// Only called from a locked context, no need to lock anything
|
||||
if(conn->txsz > 0) {
|
||||
int r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU;
|
||||
if((r = tap->picostack->__pico_socket_write(s, &conn->txbuf, max_write_len)) < 0) {
|
||||
DEBUG_ERROR("unable to write to picosock=%p", s);
|
||||
return;
|
||||
}
|
||||
int sz = (conn->txsz)-r;
|
||||
if(sz)
|
||||
memmove(&conn->txbuf, (conn->txbuf+r), sz);
|
||||
conn->txsz -= r;
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_TRANSFER
|
||||
int max = conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ;
|
||||
DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
|
||||
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Main callback for TCP connections
|
||||
void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
int err;
|
||||
Mutex::Lock _l(picotap->_tcpconns_m);
|
||||
Connection *conn = picotap->getConnection(s);
|
||||
if(!conn) {
|
||||
DEBUG_ERROR("invalid connection");
|
||||
}
|
||||
// Accept connection (analogous to lwip_nc_accept)
|
||||
if (ev & PICO_SOCK_EV_CONN) {
|
||||
DEBUG_INFO("connection established with server, picosock=%p",(conn->picosock));
|
||||
uint32_t peer;
|
||||
uint16_t port;
|
||||
struct pico_socket *client = picotap->picostack->__pico_socket_accept(s, &peer, &port);
|
||||
if(!client) {
|
||||
DEBUG_EXTRA("unable to accept conn. (event might not be incoming, not necessarily an error), picosock=%p", (conn->picosock));
|
||||
}
|
||||
ZT_PHY_SOCKFD_TYPE fds[2];
|
||||
if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
|
||||
if(errno < 0) {
|
||||
// FIXME: Return a value to the client
|
||||
//picotap->sendReturnValue(conn, -1, errno);
|
||||
DEBUG_ERROR("unable to create socketpair");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Connection *newTcpConn = new Connection();
|
||||
picotap->_Connections.push_back(newTcpConn);
|
||||
newTcpConn->type = SOCK_STREAM;
|
||||
newTcpConn->sock = picotap->_phy.wrapSocket(fds[0], newTcpConn);
|
||||
newTcpConn->picosock = client;
|
||||
int fd = picotap->_phy.getDescriptor(conn->sock);
|
||||
if(sock_fd_write(fd, fds[1]) < 0) {
|
||||
DEBUG_ERROR("error sending new fd to client application");
|
||||
}
|
||||
DEBUG_EXTRA("conn=%p, physock=%p, listen_picosock=%p, new_picosock=%p, fd=%d", newTcpConn, newTcpConn->sock, s, client, fds[1]);
|
||||
}
|
||||
if (ev & PICO_SOCK_EV_FIN) {
|
||||
DEBUG_INFO("socket closed. exit normally. picosock=%p\n\n", s);
|
||||
//picotap->__pico_timer_add(2000, compare_results, NULL);
|
||||
}
|
||||
if (ev & PICO_SOCK_EV_ERR) {
|
||||
DEBUG_INFO("socket error received" /*, strerror(pico_err)*/);
|
||||
}
|
||||
if (ev & PICO_SOCK_EV_CLOSE) {
|
||||
err = picotap->picostack->__pico_socket_close(s);
|
||||
DEBUG_INFO("socket closure = %d, picosock=%p", err, s);
|
||||
if(err==0) {
|
||||
picotap->closeConnection(conn->sock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Read from picoTCP socket
|
||||
if (ev & PICO_SOCK_EV_RD) {
|
||||
if(conn->type==SOCK_STREAM)
|
||||
pico_cb_tcp_read(picotap, s);
|
||||
if(conn->type==SOCK_DGRAM)
|
||||
pico_cb_udp_read(picotap, s);
|
||||
}
|
||||
// Write to picoTCP socket
|
||||
if (ev & PICO_SOCK_EV_WR) {
|
||||
pico_cb_tcp_write(picotap, s);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when an incoming ping is received
|
||||
/*
|
||||
static void pico_cb_ping(struct pico_icmp4_stats *s)
|
||||
{
|
||||
DEBUG_INFO();
|
||||
char host[30];
|
||||
picotap->picostack->__pico_ipv4_to_string(host, s->dst.addr);
|
||||
if (s->err == 0) {
|
||||
printf("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size,
|
||||
host, s->seq, s->ttl, (long unsigned int)s->time);
|
||||
} else {
|
||||
printf("PING %lu to %s: Error %d\n", s->seq, host, s->err);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Called from the stack, sends data to the tap device (in our case, the ZeroTier service)
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |<-------------------------| | TX
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |
|
||||
// -----------------------------------------
|
||||
int pico_eth_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_eth_hdr *ethhdr;
|
||||
ethhdr = (struct pico_eth_hdr *)buf;
|
||||
|
||||
MAC src_mac;
|
||||
MAC dest_mac;
|
||||
src_mac.setTo(ethhdr->saddr, 6);
|
||||
dest_mac.setTo(ethhdr->daddr, 6);
|
||||
|
||||
picotap->_handler(picotap->_arg,NULL,picotap->_nwid,src_mac,dest_mac,
|
||||
Utils::ntoh((uint16_t)ethhdr->proto),0, ((char*)buf) + sizeof(struct pico_eth_hdr),len - sizeof(struct pico_eth_hdr));
|
||||
return len;
|
||||
}
|
||||
|
||||
// Receives data from the tap device and encapsulates it into a ZeroTier ethernet frame and places it in a locked memory buffer
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |--------------->| | RX
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |
|
||||
// -----------------------------------------
|
||||
// It will then periodically be transfered into the network stack via pico_eth_poll()
|
||||
void pico_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
||||
{
|
||||
// Since picoTCP only allows the reception of frames from within the polling function, we
|
||||
// must enqueue each frame into a memory structure shared by both threads. This structure will
|
||||
Mutex::Lock _l(tap->_pico_frame_rxbuf_m);
|
||||
|
||||
// assemble new eth header
|
||||
struct pico_eth_hdr ethhdr;
|
||||
from.copyTo(ethhdr.saddr, 6);
|
||||
to.copyTo(ethhdr.daddr, 6);
|
||||
ethhdr.proto = Utils::hton((uint16_t)etherType);
|
||||
int newlen = len + sizeof(int) + sizeof(struct pico_eth_hdr);
|
||||
|
||||
int mylen;
|
||||
while(newlen > (MAX_PICO_FRAME_RX_BUF_SZ-tap->pico_frame_rxbuf_tot) && ethhdr.proto == 56710)
|
||||
{
|
||||
mylen = 0;
|
||||
//DEBUG_FLOW(" [ ZTWIRE -> FBUF ] not enough space left on RX frame buffer, dropping oldest packet in buffer");
|
||||
/*
|
||||
memcpy(&mylen, picotap->pico_frame_rxbuf, sizeof(len));
|
||||
memmove(tap->pico_frame_rxbuf, tap->pico_frame_rxbuf + mylen, MAX_PICO_FRAME_RX_BUF_SZ-mylen); // shift buffer
|
||||
picotap->pico_frame_rxbuf_tot-=mylen;
|
||||
*/
|
||||
memset(tap->pico_frame_rxbuf,0,MAX_PICO_FRAME_RX_BUF_SZ);
|
||||
picotap->pico_frame_rxbuf_tot=0;
|
||||
}
|
||||
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot, &newlen, sizeof(newlen)); // size of frame + meta
|
||||
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen), ðhdr, sizeof(ethhdr)); // new eth header
|
||||
memcpy(tap->pico_frame_rxbuf + tap->pico_frame_rxbuf_tot + sizeof(newlen) + sizeof(ethhdr), data, len); // frame data
|
||||
tap->pico_frame_rxbuf_tot += newlen;
|
||||
DEBUG_FLOW(" [ ZTWIRE -> FBUF ] Move FRAME(sz=%d) into FBUF(sz=%d), data_len=%d", newlen, picotap->pico_frame_rxbuf_tot, len);
|
||||
}
|
||||
|
||||
// Called periodically by the stack, this removes data from the locked memory buffer (FBUF) and feeds it into the stack.
|
||||
// A maximum of 'loop_score' frames can be processed in each call
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |----------------->| | RX
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |
|
||||
// -----------------------------------------
|
||||
int pico_eth_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
// OPTIMIZATION: The copy logic and/or buffer structure should be reworked for better performance after the BETA
|
||||
// NetconEthernetTap *tap = (NetconEthernetTap*)netif->state;
|
||||
Mutex::Lock _l(picotap->_pico_frame_rxbuf_m);
|
||||
unsigned char frame[SDK_MTU];
|
||||
int len;
|
||||
while (picotap->pico_frame_rxbuf_tot > 0 && loop_score > 0) {
|
||||
//DEBUG_FLOW(" [ FBUF -> STACK] Frame buffer SZ=%d", picotap->pico_frame_rxbuf_tot);
|
||||
memset(frame, 0, sizeof(frame));
|
||||
len = 0;
|
||||
memcpy(&len, picotap->pico_frame_rxbuf, sizeof(len)); // get frame len
|
||||
if(len >= 0) {
|
||||
//DEBUG_FLOW(" [ FBUF -> STACK] Moving FRAME of size (%d) from FBUF(sz=%d) into stack",len, picotap->pico_frame_rxbuf_tot-len);
|
||||
memcpy(frame, picotap->pico_frame_rxbuf + sizeof(len), len-(sizeof(len)) ); // get frame data
|
||||
memmove(picotap->pico_frame_rxbuf, picotap->pico_frame_rxbuf + len, MAX_PICO_FRAME_RX_BUF_SZ-len); // shift buffer
|
||||
picotap->picostack->__pico_stack_recv(dev, (uint8_t*)frame, (len-sizeof(len)));
|
||||
picotap->pico_frame_rxbuf_tot-=len;
|
||||
}
|
||||
else {
|
||||
DEBUG_ERROR("Skipping frame of size (%d)",len);
|
||||
exit(0);
|
||||
}
|
||||
loop_score--;
|
||||
}
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
// Creates a new pico_socket and Connection object to represent a new connection to be.
|
||||
Connection *pico_handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc)
|
||||
{
|
||||
struct pico_socket * psock;
|
||||
int protocol, protocol_version;
|
||||
|
||||
#if defined(SDK_IPV4)
|
||||
protocol_version = PICO_PROTO_IPV4;
|
||||
#elif defined(SDK_IPV6)
|
||||
protocol_version = PICO_PROTO_IPV6;
|
||||
#endif
|
||||
if(socket_rpc->socket_type == SOCK_DGRAM) {
|
||||
protocol = PICO_PROTO_UDP;
|
||||
psock = picotap->picostack->__pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity);
|
||||
}
|
||||
if(socket_rpc->socket_type == SOCK_STREAM) {
|
||||
protocol = PICO_PROTO_TCP;
|
||||
psock = picotap->picostack->__pico_socket_open(protocol_version, protocol, &pico_cb_socket_activity);
|
||||
}
|
||||
|
||||
if(psock) {
|
||||
DEBUG_ATTN("physock=%p, picosock=%p", sock, psock);
|
||||
Connection * newConn = new Connection();
|
||||
*uptr = newConn;
|
||||
newConn->type = socket_rpc->socket_type;
|
||||
newConn->sock = sock;
|
||||
|
||||
/*
|
||||
int res = 0;
|
||||
int sendbuff = UNIX_SOCK_BUF_SIZE;
|
||||
socklen_t optlen = sizeof(sendbuff);
|
||||
|
||||
res = setsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff));
|
||||
if(res == -1)
|
||||
//DEBUG_ERROR("Error while setting RX buffer limits");
|
||||
res = setsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
|
||||
if(res == -1)
|
||||
//DEBUG_ERROR("Error while setting TX buffer limits");
|
||||
|
||||
// Get buffer size
|
||||
// optlen = sizeof(sendbuff);
|
||||
// res = getsockopt(picotap->_phy.getDescriptor(sock), SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
|
||||
// DEBUG_INFO("buflen=%d", sendbuff);
|
||||
*/
|
||||
|
||||
newConn->local_addr = NULL;
|
||||
newConn->picosock = psock;
|
||||
picotap->_Connections.push_back(newConn);
|
||||
memset(newConn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ);
|
||||
return newConn;
|
||||
}
|
||||
else
|
||||
DEBUG_ERROR("failed to create pico_socket");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Writes data from the I/O buffer to the network stack
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |----------------->| | TX
|
||||
// -----------------------------------------
|
||||
void pico_handleWrite(Connection *conn)
|
||||
{
|
||||
if(!conn || !conn->picosock) {
|
||||
DEBUG_ERROR(" invalid connection");
|
||||
return;
|
||||
}
|
||||
|
||||
int max, r, max_write_len = conn->txsz < SDK_MTU ? conn->txsz : SDK_MTU;
|
||||
if((r = picotap->picostack->__pico_socket_write(conn->picosock, &conn->txbuf, max_write_len)) < 0) {
|
||||
DEBUG_ERROR("unable to write to picosock=%p, r=%d", (conn->picosock), r);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Errors
|
||||
|
||||
/*
|
||||
if(pico_err == PICO_ERR_EINVAL)
|
||||
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
|
||||
if(pico_err == PICO_ERR_EIO)
|
||||
DEBUG_ERROR("PICO_ERR_EIO - input/output error");
|
||||
if(pico_err == PICO_ERR_ENOTCONN)
|
||||
DEBUG_ERROR("PICO_ERR_ENOTCONN - the socket is not connected");
|
||||
if(pico_err == PICO_ERR_ESHUTDOWN)
|
||||
DEBUG_ERROR("PICO_ERR_ESHUTDOWN - cannot send after transport endpoint shutdown");
|
||||
if(pico_err == PICO_ERR_EADDRNOTAVAIL)
|
||||
DEBUG_ERROR("PICO_ERR_EADDRNOTAVAIL - address not available");
|
||||
if(pico_err == PICO_ERR_EHOSTUNREACH)
|
||||
DEBUG_ERROR("PICO_ERR_EHOSTUNREACH - host is unreachable");
|
||||
if(pico_err == PICO_ERR_ENOMEM)
|
||||
DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space");
|
||||
if(pico_err == PICO_ERR_EAGAIN)
|
||||
DEBUG_ERROR("PICO_ERR_EAGAIN - resource temporarily unavailable");
|
||||
*/
|
||||
|
||||
// adjust buffer
|
||||
int sz = (conn->txsz)-r;
|
||||
if(sz)
|
||||
memmove(&conn->txbuf, (conn->txbuf+r), sz);
|
||||
conn->txsz -= r;
|
||||
|
||||
if(conn->type == SOCK_STREAM) {
|
||||
max = DEFAULT_TCP_TX_BUF_SZ;
|
||||
DEBUG_TRANS("[TCP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
|
||||
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
|
||||
}
|
||||
if(conn->type == SOCK_DGRAM) {
|
||||
max = DEFAULT_UDP_TX_BUF_SZ;
|
||||
DEBUG_TRANS("[UDP TX] ---> :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
|
||||
(float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, r);
|
||||
}
|
||||
}
|
||||
|
||||
// Instructs the stack to connect to a remote host
|
||||
void pico_handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc)
|
||||
{
|
||||
if(conn->picosock) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &connect_rpc->addr;
|
||||
int ret;
|
||||
// TODO: Rewrite this
|
||||
#if defined(SDK_IPV4)
|
||||
struct pico_ip4 zaddr;
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in*)&connect_rpc->addr;
|
||||
char ipv4_str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN);
|
||||
picotap->picostack->__pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
|
||||
//DEBUG_ATTN("addr=%s:%d", ipv4_str, Utils::ntoh(addr->sin_port));
|
||||
ret = picotap->picostack->__pico_socket_connect(conn->picosock, &zaddr, addr->sin_port);
|
||||
#elif defined(SDK_IPV6) // "fd56:5799:d8f6:1238:8c99:9322:30ce:418a"
|
||||
struct pico_ip6 zaddr;
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&connect_rpc->addr;
|
||||
char ipv6_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
|
||||
picotap->picostack->__pico_string_to_ipv6(ipv6_str, zaddr.addr);
|
||||
//DEBUG_ATTN("addr=%s:%d", ipv6_str, Utils::ntoh(addr->sin_port));
|
||||
ret = picotap->picostack->__pico_socket_connect(conn->picosock, &zaddr, addr->sin_port);
|
||||
#endif
|
||||
|
||||
memcpy(&(conn->peer_addr), &connect_rpc->addr, sizeof(struct sockaddr_storage));
|
||||
|
||||
if(ret == PICO_ERR_EPROTONOSUPPORT)
|
||||
DEBUG_ERROR("PICO_ERR_EPROTONOSUPPORT");
|
||||
if(ret == PICO_ERR_EINVAL)
|
||||
DEBUG_ERROR("PICO_ERR_EINVAL");
|
||||
if(ret == PICO_ERR_EHOSTUNREACH)
|
||||
DEBUG_ERROR("PICO_ERR_EHOSTUNREACH");
|
||||
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), 0, ERR_OK);
|
||||
}
|
||||
}
|
||||
|
||||
// Instructs the stack to bind to a given address
|
||||
void pico_handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc)
|
||||
{
|
||||
Connection *conn = picotap->getConnection(sock);
|
||||
if(!sock) {
|
||||
DEBUG_ERROR("invalid connection");
|
||||
return;
|
||||
}
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &bind_rpc->addr;
|
||||
int ret;
|
||||
// TODO: Rewrite this
|
||||
#if defined(SDK_IPV4)
|
||||
struct pico_ip4 zaddr;
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in*)&bind_rpc->addr;
|
||||
char ipv4_str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &(in4->sin_addr), ipv4_str, INET_ADDRSTRLEN);
|
||||
picotap->picostack->__pico_string_to_ipv4(ipv4_str, &(zaddr.addr));
|
||||
DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv4_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
|
||||
ret = picotap->picostack->__pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port));
|
||||
#elif defined(SDK_IPV6)
|
||||
struct pico_ip6 zaddr;
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&bind_rpc->addr;
|
||||
char ipv6_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &(in6->sin6_addr), ipv6_str, INET6_ADDRSTRLEN);
|
||||
picotap->picostack->__pico_string_to_ipv6(ipv6_str, zaddr.addr);
|
||||
DEBUG_ATTN("addr=%s:%d, physock=%p, picosock=%p", ipv6_str, Utils::ntoh(addr->sin_port), sock, (conn->picosock));
|
||||
ret = picotap->picostack->__pico_socket_bind(conn->picosock, &zaddr, (uint16_t*)&(addr->sin_port));
|
||||
#endif
|
||||
if(ret < 0) {
|
||||
DEBUG_ERROR("unable to bind pico_socket(%p), err=%d", (conn->picosock), ret);
|
||||
if(ret == PICO_ERR_EINVAL) {
|
||||
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL);
|
||||
}
|
||||
if(ret == PICO_ERR_ENOMEM) {
|
||||
DEBUG_ERROR("PICO_ERR_ENOMEM - not enough space");
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENOMEM);
|
||||
}
|
||||
if(ret == PICO_ERR_ENXIO) {
|
||||
DEBUG_ERROR("PICO_ERR_ENXIO - no such device or address");
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, ENXIO);
|
||||
}
|
||||
}
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success
|
||||
}
|
||||
|
||||
// Puts a pico_socket into a listening state to receive incoming connection requests
|
||||
void pico_handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc)
|
||||
{
|
||||
Connection *conn = picotap->getConnection(sock);
|
||||
DEBUG_ATTN("physock=%p, conn=%p, picosock=%p", sock, conn, conn->picosock);
|
||||
if(!sock || !conn) {
|
||||
DEBUG_ERROR("invalid connection");
|
||||
return;
|
||||
}
|
||||
int ret, backlog = 100;
|
||||
if((ret = picotap->picostack->__pico_socket_listen(conn->picosock, backlog)) < 0)
|
||||
{
|
||||
if(ret == PICO_ERR_EINVAL) {
|
||||
DEBUG_ERROR("PICO_ERR_EINVAL - invalid argument");
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EINVAL);
|
||||
}
|
||||
if(ret == PICO_ERR_EISCONN) {
|
||||
DEBUG_ERROR("PICO_ERR_EISCONN - socket is connected");
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), -1, EISCONN);
|
||||
}
|
||||
}
|
||||
picotap->sendReturnValue(picotap->_phy.getDescriptor(rpcSock), ERR_OK, ERR_OK); // success
|
||||
}
|
||||
|
||||
// Feeds data into the local app socket from the I/O buffer associated with the "connection"
|
||||
// [ (APP<-ZTSOCK) <- RXBUF ]
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |<---------------| | RX
|
||||
// -----------------------------------------
|
||||
void pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked)
|
||||
{
|
||||
if(!lwip_invoked) {
|
||||
// The stack thread writes to RXBUF as well
|
||||
picotap->_tcpconns_m.lock();
|
||||
picotap->_rx_buf_m.lock();
|
||||
}
|
||||
int tot = 0, n = -1, write_attempts = 0;
|
||||
|
||||
Connection *conn = picotap->getConnection(sock);
|
||||
if(conn && conn->rxsz) {
|
||||
|
||||
//
|
||||
if(conn->type==SOCK_DGRAM) {
|
||||
// Try to write SDK_MTU-sized chunk to app socket
|
||||
while(tot < SDK_MTU) {
|
||||
write_attempts++;
|
||||
n = picotap->_phy.streamSend(conn->sock, (conn->rxbuf)+tot, SDK_MTU);
|
||||
tot += n;
|
||||
DEBUG_FLOW(" [ ZTSOCK <- RXBUF] wrote = %d, errno=%d", n, errno);
|
||||
// If socket is unavailable, attempt to write N times before giving up
|
||||
if(errno==35) {
|
||||
if(write_attempts == 1024) {
|
||||
n = SDK_MTU; // say we wrote it, even though we didn't (drop packet)
|
||||
tot = SDK_MTU;
|
||||
}
|
||||
}
|
||||
}
|
||||
int payload_sz, addr_sz_offset = sizeof(struct sockaddr_storage);
|
||||
memcpy(&payload_sz, conn->rxbuf + addr_sz_offset, sizeof(int));
|
||||
struct sockaddr_storage addr;
|
||||
memcpy(&addr, conn->rxbuf, addr_sz_offset);
|
||||
// adjust buffer
|
||||
//DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Copying data from receiving buffer to ZT-controlled app socket (n=%d, payload_sz=%d)", n, payload_sz);
|
||||
if(conn->rxsz-n > 0) { // If more remains on buffer
|
||||
memcpy(conn->rxbuf, conn->rxbuf+SDK_MTU, conn->rxsz - SDK_MTU);
|
||||
//DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Data(%d) still on buffer, moving it up by one MTU", conn->rxsz-n);
|
||||
////memset(conn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ);
|
||||
////conn->rxsz=SDK_MTU;
|
||||
}
|
||||
conn->rxsz -= SDK_MTU;
|
||||
}
|
||||
//
|
||||
if(conn->type==SOCK_STREAM) {
|
||||
n = picotap->_phy.streamSend(conn->sock, conn->rxbuf, conn->rxsz);
|
||||
if(conn->rxsz-n > 0) // If more remains on buffer
|
||||
memcpy(conn->rxbuf, conn->rxbuf+n, conn->rxsz - n);
|
||||
conn->rxsz -= n;
|
||||
}
|
||||
// Notify ZT I/O loop that it has new buffer contents
|
||||
if(n) {
|
||||
if(conn->type==SOCK_STREAM) {
|
||||
|
||||
#if DEBUG_LEVEL >= MSG_TRANSFER
|
||||
float max = conn->type == SOCK_STREAM ? (float)DEFAULT_TCP_RX_BUF_SZ : (float)DEFAULT_UDP_RX_BUF_SZ;
|
||||
DEBUG_TRANS("[TCP RX] <--- :: {TX: %.3f%%, RX: %.3f%%, physock=%p} :: %d bytes",
|
||||
(float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n);
|
||||
#endif
|
||||
}
|
||||
if(conn->rxsz == 0) {
|
||||
picotap->_phy.setNotifyWritable(sock, false);
|
||||
}
|
||||
else {
|
||||
picotap->_phy.setNotifyWritable(sock, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
picotap->_phy.setNotifyWritable(sock, false);
|
||||
}
|
||||
}
|
||||
if(!lwip_invoked) {
|
||||
picotap->_tcpconns_m.unlock();
|
||||
picotap->_rx_buf_m.unlock();
|
||||
}
|
||||
DEBUG_FLOW(" [ ZTSOCK <- RXBUF] Emitted (%d) from RXBUF(%d) to socket", tot, conn->rxsz);
|
||||
}
|
||||
|
||||
// Closes a pico_socket
|
||||
void pico_handleClose(PhySocket *sock)
|
||||
{
|
||||
/*
|
||||
int ret;
|
||||
if(conn && conn->picosock) {
|
||||
if((ret = picotap->picostack->__pico_socket_close(conn->picosock)) < 0) {
|
||||
DEBUG_ERROR("error closing pico_socket(%p)", (void*)(conn->picosock));
|
||||
// sendReturnValue()
|
||||
}
|
||||
return;
|
||||
}
|
||||
DEBUG_ERROR("invalid connection or pico_socket");
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDK_PICOTCP
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef SDK_PICOSTACK_H
|
||||
#define SDK_PICOSTACK_H
|
||||
|
||||
#if defined(SDK_PICOTCP)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef D_GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "Constants.hpp"
|
||||
#include "Phy.hpp"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "pico_stack.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_icmp4.h"
|
||||
#include "pico_dev_tap.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_ipv6.h"
|
||||
|
||||
#include "tap.hpp"
|
||||
|
||||
// picoTCP API function signatures
|
||||
#define PICO_IPV4_TO_STRING_SIG char *ipbuf, const uint32_t ip
|
||||
#define PICO_TAP_CREATE_SIG char *name
|
||||
#define PICO_IPV4_LINK_ADD_SIG struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask
|
||||
#define PICO_DEVICE_INIT_SIG struct pico_device *dev, const char *name, uint8_t *mac
|
||||
#define PICO_STACK_RECV_SIG struct pico_device *dev, uint8_t *buffer, uint32_t len
|
||||
#define PICO_ICMP4_PING_SIG char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)
|
||||
#define PICO_TIMER_ADD_SIG pico_time expire, void (*timer)(pico_time, void *), void *arg
|
||||
#define PICO_STRING_TO_IPV4_SIG const char *ipstr, uint32_t *ip
|
||||
#define PICO_STRING_TO_IPV6_SIG const char *ipstr, uint8_t *ip
|
||||
#define PICO_SOCKET_SETOPTION_SIG struct pico_socket *s, int option, void *value
|
||||
#define PICO_SOCKET_SEND_SIG struct pico_socket *s, const void *buf, int len
|
||||
#define PICO_SOCKET_SENDTO_SIG struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port
|
||||
#define PICO_SOCKET_RECV_SIG struct pico_socket *s, void *buf, int len
|
||||
#define PICO_SOCKET_RECVFROM_SIG struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port
|
||||
#define PICO_SOCKET_OPEN_SIG uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)
|
||||
#define PICO_SOCKET_BIND_SIG struct pico_socket *s, void *local_addr, uint16_t *port
|
||||
#define PICO_SOCKET_CONNECT_SIG struct pico_socket *s, const void *srv_addr, uint16_t remote_port
|
||||
#define PICO_SOCKET_LISTEN_SIG struct pico_socket *s, const int backlog
|
||||
#define PICO_SOCKET_READ_SIG struct pico_socket *s, void *buf, int len
|
||||
#define PICO_SOCKET_WRITE_SIG struct pico_socket *s, const void *buf, int len
|
||||
#define PICO_SOCKET_CLOSE_SIG struct pico_socket *s
|
||||
#define PICO_SOCKET_SHUTDOWN_SIG struct pico_socket *s, int mode
|
||||
#define PICO_SOCKET_ACCEPT_SIG struct pico_socket *s, void *orig, uint16_t *port
|
||||
#define PICO_IPV6_LINK_ADD_SIG struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask
|
||||
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class NetconEthernetTap;
|
||||
struct Connection;
|
||||
|
||||
// Driver function prototypes
|
||||
int pico_eth_send(struct pico_device *dev, void *buf, int len);
|
||||
int pico_eth_poll(struct pico_device *dev, int loop_score);
|
||||
void pico_init_interface(NetconEthernetTap *tap, const InetAddress &ip);
|
||||
void pico_loop(NetconEthernetTap *tap);
|
||||
void pico_cb_tcp_read(NetconEthernetTap *tap, struct pico_socket *s);
|
||||
void pico_cb_udp_read(NetconEthernetTap *tap, struct pico_socket *s);
|
||||
void pico_cb_tcp_write(NetconEthernetTap *tap, struct pico_socket *s);
|
||||
void pico_cb_socket_activity(uint16_t ev, struct pico_socket *s);
|
||||
|
||||
int pico_eth_send(struct pico_device *dev, void *buf, int len);
|
||||
void pico_rx(NetconEthernetTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
int pico_eth_poll(struct pico_device *dev, int loop_score);
|
||||
Connection *pico_handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
|
||||
void pico_handleWrite(Connection *conn);
|
||||
void pico_handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc);
|
||||
void pico_handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc);
|
||||
void pico_handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc);
|
||||
void pico_handleRead(PhySocket *sock,void **uptr,bool lwip_invoked);
|
||||
void pico_handleClose(PhySocket *sock);
|
||||
|
||||
|
||||
/**
|
||||
* Loads an instance of picoTCP stack library in a private memory arena
|
||||
*
|
||||
* This uses dlmopen() to load an instance of the LWIP stack into its
|
||||
* own private memory space. This is done to get around the stack's
|
||||
* lack of thread-safety or multi-instance support. The alternative
|
||||
* would be to massively refactor the stack so everything lives in a
|
||||
* state object instead of static memory space.
|
||||
*/
|
||||
class picoTCP_stack
|
||||
{
|
||||
public:
|
||||
|
||||
void *_libref;
|
||||
|
||||
void close() {
|
||||
#if defined(__STATIC_STACK__)
|
||||
return;
|
||||
#elif defined(__DYNAMIC_STACK__)
|
||||
dlclose(_libref);
|
||||
#endif
|
||||
}
|
||||
|
||||
void (*_pico_stack_init)(void);
|
||||
void (*_pico_stack_tick)(void);
|
||||
int (*_pico_string_to_ipv4)(PICO_STRING_TO_IPV4_SIG);
|
||||
int (*_pico_ipv4_to_string)(PICO_IPV4_TO_STRING_SIG);
|
||||
int (*_pico_ipv4_link_add)(PICO_IPV4_LINK_ADD_SIG);
|
||||
int (*_pico_device_init)(PICO_DEVICE_INIT_SIG);
|
||||
int32_t (*_pico_stack_recv)(PICO_STACK_RECV_SIG);
|
||||
int (*_pico_icmp4_ping)(PICO_ICMP4_PING_SIG);
|
||||
int (*_pico_string_to_ipv6)(PICO_STRING_TO_IPV6_SIG);
|
||||
int (*_pico_socket_setoption)(PICO_SOCKET_SETOPTION_SIG);
|
||||
uint32_t (*_pico_timer_add)(PICO_TIMER_ADD_SIG);
|
||||
int (*_pico_socket_send)(PICO_SOCKET_SEND_SIG);
|
||||
int (*_pico_socket_sendto)(PICO_SOCKET_SENDTO_SIG);
|
||||
int (*_pico_socket_recv)(PICO_SOCKET_RECV_SIG);
|
||||
int (*_pico_socket_recvfrom)(PICO_SOCKET_RECVFROM_SIG);
|
||||
struct pico_socket * (*_pico_socket_open)(PICO_SOCKET_OPEN_SIG);
|
||||
int (*_pico_socket_bind)(PICO_SOCKET_BIND_SIG);
|
||||
int (*_pico_socket_connect)(PICO_SOCKET_CONNECT_SIG);
|
||||
int (*_pico_socket_listen)(PICO_SOCKET_LISTEN_SIG);
|
||||
int (*_pico_socket_read)(PICO_SOCKET_READ_SIG);
|
||||
int (*_pico_socket_write)(PICO_SOCKET_WRITE_SIG);
|
||||
int (*_pico_socket_close)(PICO_SOCKET_CLOSE_SIG);
|
||||
int (*_pico_socket_shutdown)(PICO_SOCKET_SHUTDOWN_SIG);
|
||||
struct pico_socket *(*_pico_socket_accept)(PICO_SOCKET_ACCEPT_SIG);
|
||||
int (*_pico_ipv6_link_add)(PICO_IPV6_LINK_ADD_SIG);
|
||||
|
||||
Mutex _lock;
|
||||
Mutex _lock_mem;
|
||||
|
||||
picoTCP_stack(const char* path) :
|
||||
_libref(NULL)
|
||||
{
|
||||
#if defined(__ANDROID__) || defined(__UNITY_3D__)
|
||||
#define __STATIC_STACK__
|
||||
#elif defined(__linux__) && !defined(SDK_BUNDLED)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load stack library
|
||||
DEBUG_ATTN("loading network stack library (%s)", path);
|
||||
_libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW);
|
||||
#elif defined(__linux__) && defined(SDK_BUNDLED) // TODO: Determine why __STATIC_STACK__ won't work in SDK_BUNDLED mode
|
||||
#define __DYNAMIC_STACK__
|
||||
DEBUG_ATTN("loading network stack library (%s)", path);
|
||||
_libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW);
|
||||
#elif defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#include "node/Mutex.hpp"
|
||||
#define __STATIC_STACK__
|
||||
// iOS Simulator or iOS device
|
||||
// Do nothing, symbols are statically-linked
|
||||
#elif TARGET_OS_MAC && !defined(SDK_BUNDLED)
|
||||
#define __DYNAMIC_STACK__
|
||||
// Dynamically load stack library
|
||||
DEBUG_ATTN("loading network stack library (%s)", path);
|
||||
_libref = dlopen(path, RTLD_NOW);
|
||||
#else
|
||||
#define __DYNAMIC_STACK__ // should be switched to __STATIC_STACK__
|
||||
DEBUG_ATTN("loading network stack library (%s)", path);
|
||||
_libref = dlopen(path, RTLD_NOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __STATIC_STACK__ // Set static references (for use in iOS)
|
||||
|
||||
_pico_stack_init = (void(*)(void))&pico_stack_init;
|
||||
_pico_stack_tick = (void(*)(void))&pico_stack_tick;
|
||||
_pico_string_to_ipv4 = (int(*)(PICO_STRING_TO_IPV4_SIG))&pico_string_to_ipv4;
|
||||
_pico_ipv4_to_string = (int(*)(PICO_IPV4_TO_STRING_SIG))&pico_ipv4_to_string;
|
||||
_pico_ipv4_link_add = (int(*)(PICO_IPV4_LINK_ADD_SIG))&pico_ipv4_link_add;
|
||||
_pico_device_init = (int(*)(PICO_DEVICE_INIT_SIG))&pico_device_init;
|
||||
_pico_stack_recv = (int32_t(*)(PICO_STACK_RECV_SIG))&pico_stack_recv;
|
||||
_pico_icmp4_ping = (int(*)(PICO_ICMP4_PING_SIG))&pico_icmp4_ping;
|
||||
_pico_string_to_ipv6 = (int(*)(PICO_STRING_TO_IPV6_SIG))&pico_string_to_ipv6;
|
||||
_pico_socket_setoption = (int(*)(PICO_SOCKET_SETOPTION_SIG))&pico_socket_setoption;
|
||||
_pico_timer_add = (uint32_t(*)(PICO_TIMER_ADD_SIG))&pico_timer_add;
|
||||
_pico_socket_send = (int(*)(PICO_SOCKET_SEND_SIG))&pico_socket_send;
|
||||
_pico_socket_sendto = (int(*)(PICO_SOCKET_SENDTO_SIG))&pico_socket_sendto;
|
||||
_pico_socket_recv = (int(*)(PICO_SOCKET_RECV_SIG))&pico_socket_recv;
|
||||
_pico_socket_recvfrom = (int32_t(*)(PICO_SOCKET_RECVFROM_SIG))&pico_socket_recvfrom;
|
||||
_pico_socket_open = (struct pico_socket*(*)(PICO_SOCKET_OPEN_SIG))&pico_socket_open;
|
||||
_pico_socket_bind = (int(*)(PICO_SOCKET_BIND_SIG))&pico_socket_bind;
|
||||
_pico_socket_connect = (int(*)(PICO_SOCKET_CONNECT_SIG))&pico_socket_connect;
|
||||
_pico_socket_listen = (int(*)(PICO_SOCKET_LISTEN_SIG))&pico_socket_listen;
|
||||
_pico_socket_read = (int(*)(PICO_SOCKET_READ_SIG))&pico_socket_read;
|
||||
_pico_socket_write = (int(*)(PICO_SOCKET_WRITE_SIG))&pico_socket_write;
|
||||
_pico_socket_close = (int(*)(PICO_SOCKET_CLOSE_SIG))&pico_socket_close;
|
||||
_pico_socket_shutdown = (int(*)(PICO_SOCKET_SHUTDOWN_SIG))&pico_socket_shutdown;
|
||||
_pico_socket_accept = (struct pico_socket*(*)(PICO_SOCKET_ACCEPT_SIG))&pico_socket_accept;
|
||||
_pico_ipv6_link_add = (int(*)(PICO_IPV6_LINK_ADD_SIG))&pico_ipv6_link_add;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __DYNAMIC_STACK__ // Use dynamically-loaded symbols (for use in normal desktop applications)
|
||||
|
||||
if(_libref == NULL)
|
||||
DEBUG_ERROR("dlerror(): %s", dlerror());
|
||||
|
||||
_pico_stack_init = (void(*)(void))dlsym(_libref, "pico_stack_init");
|
||||
_pico_stack_tick = (void(*)(void))dlsym(_libref, "pico_stack_tick");
|
||||
_pico_string_to_ipv4 = (int(*)(PICO_STRING_TO_IPV4_SIG))dlsym(_libref, "pico_string_to_ipv4");
|
||||
_pico_ipv4_to_string = (int(*)(PICO_IPV4_TO_STRING_SIG))dlsym(_libref, "pico_ipv4_to_string");
|
||||
_pico_ipv4_link_add = (int(*)(PICO_IPV4_LINK_ADD_SIG))dlsym(_libref, "pico_ipv4_link_add");
|
||||
_pico_device_init = (int(*)(PICO_DEVICE_INIT_SIG))dlsym(_libref, "pico_device_init");
|
||||
_pico_stack_recv = (int32_t(*)(PICO_STACK_RECV_SIG))dlsym(_libref, "pico_stack_recv");
|
||||
_pico_icmp4_ping = (int(*)(PICO_ICMP4_PING_SIG))dlsym(_libref, "pico_icmp4_ping");
|
||||
_pico_string_to_ipv6 = (int(*)(PICO_STRING_TO_IPV6_SIG))dlsym(_libref, "pico_string_to_ipv6");
|
||||
_pico_socket_setoption = (int(*)(PICO_SOCKET_SETOPTION_SIG))dlsym(_libref, "pico_socket_setoption");
|
||||
_pico_timer_add = (uint32_t(*)(PICO_TIMER_ADD_SIG))dlsym(_libref, "pico_timer_add");
|
||||
_pico_socket_send = (int(*)(PICO_SOCKET_SEND_SIG))dlsym(_libref, "pico_socket_send");
|
||||
_pico_socket_sendto = (int(*)(PICO_SOCKET_SENDTO_SIG))dlsym(_libref, "pico_socket_sendto");
|
||||
_pico_socket_recv = (int(*)(PICO_SOCKET_RECV_SIG))dlsym(_libref, "pico_socket_recv");
|
||||
_pico_socket_recvfrom = (int32_t(*)(PICO_SOCKET_RECVFROM_SIG))dlsym(_libref, "pico_socket_recvfrom");
|
||||
_pico_socket_open = (struct pico_socket*(*)(PICO_SOCKET_OPEN_SIG))dlsym(_libref, "pico_socket_open");
|
||||
_pico_socket_bind = (int(*)(PICO_SOCKET_BIND_SIG))dlsym(_libref, "pico_socket_bind");
|
||||
_pico_socket_connect = (int(*)(PICO_SOCKET_CONNECT_SIG))dlsym(_libref, "pico_socket_connect");
|
||||
_pico_socket_listen = (int(*)(PICO_SOCKET_LISTEN_SIG))dlsym(_libref, "pico_socket_listen");
|
||||
_pico_socket_read = (int(*)(PICO_SOCKET_READ_SIG))dlsym(_libref, "pico_socket_read");
|
||||
_pico_socket_write = (int(*)(PICO_SOCKET_WRITE_SIG))dlsym(_libref, "pico_socket_write");
|
||||
_pico_socket_close = (int(*)(PICO_SOCKET_CLOSE_SIG))dlsym(_libref, "pico_socket_close");
|
||||
_pico_socket_shutdown = (int(*)(PICO_SOCKET_SHUTDOWN_SIG))dlsym(_libref, "pico_socket_shutdown");
|
||||
_pico_socket_accept = (struct pico_socket*(*)(PICO_SOCKET_ACCEPT_SIG))dlsym(_libref, "pico_socket_accept");
|
||||
_pico_ipv6_link_add = (int(*)(PICO_IPV6_LINK_ADD_SIG))dlsym(_libref, "pico_ipv6_link_add");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~picoTCP_stack()
|
||||
{
|
||||
if (_libref)
|
||||
dlclose(_libref);
|
||||
}
|
||||
|
||||
inline void __pico_stack_init(void) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); _pico_stack_init(); }
|
||||
inline void __pico_stack_tick(void) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); _pico_stack_tick(); }
|
||||
inline int __pico_ipv4_to_string(PICO_IPV4_TO_STRING_SIG) throw() {/* DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_ipv4_to_string(ipbuf, ip); }
|
||||
inline int __pico_ipv4_link_add(PICO_IPV4_LINK_ADD_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_ipv4_link_add(dev, address, netmask); }
|
||||
inline int __pico_device_init(PICO_DEVICE_INIT_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_device_init(dev, name, mac); }
|
||||
inline int __pico_stack_recv(PICO_STACK_RECV_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_stack_recv(dev, buffer, len); }
|
||||
inline int __pico_icmp4_ping(PICO_ICMP4_PING_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_icmp4_ping(dst, count, interval, timeout, size, cb); }
|
||||
inline int __pico_string_to_ipv4(PICO_STRING_TO_IPV4_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_string_to_ipv4(ipstr, ip); }
|
||||
inline int __pico_string_to_ipv6(PICO_STRING_TO_IPV6_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_string_to_ipv6(ipstr, ip); }
|
||||
inline int __pico_socket_setoption(PICO_SOCKET_SETOPTION_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_setoption(s, option, value); }
|
||||
inline uint32_t __pico_timer_add(PICO_TIMER_ADD_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_timer_add(expire, timer, arg); }
|
||||
inline int __pico_socket_send(PICO_SOCKET_SEND_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_send(s, buf, len); }
|
||||
inline int __pico_socket_sendto(PICO_SOCKET_SENDTO_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_sendto(s, buf, len, dst, remote_port); }
|
||||
inline int __pico_socket_recv(PICO_SOCKET_RECV_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_recv(s, buf, len); }
|
||||
inline int __pico_socket_recvfrom(PICO_SOCKET_RECVFROM_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_recvfrom(s, buf, len, orig, remote_port); }
|
||||
inline struct pico_socket * __pico_socket_open(PICO_SOCKET_OPEN_SIG) throw() { /*DEBUG_ATTN();*/ return _pico_socket_open(net, proto, wakeup); }
|
||||
inline int __pico_socket_bind(PICO_SOCKET_BIND_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_bind(s, local_addr, port); }
|
||||
inline int __pico_socket_connect(PICO_SOCKET_CONNECT_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_connect(s, srv_addr, remote_port); }
|
||||
inline int __pico_socket_listen(PICO_SOCKET_LISTEN_SIG) throw() { /*DEBUG_ATTN();*/ Mutex::Lock _l(_lock); return _pico_socket_listen(s, backlog); }
|
||||
inline int __pico_socket_read(PICO_SOCKET_READ_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock); */ return _pico_socket_read(s, buf, len); }
|
||||
inline int __pico_socket_write(PICO_SOCKET_WRITE_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_write(s, buf, len); }
|
||||
inline int __pico_socket_close(PICO_SOCKET_CLOSE_SIG) throw() { /*DEBUG_STACK();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_close(s); }
|
||||
inline int __pico_socket_shutdown(PICO_SOCKET_SHUTDOWN_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_socket_shutdown(s, mode); }
|
||||
inline struct pico_socket * __pico_socket_accept(PICO_SOCKET_ACCEPT_SIG) throw() { /*DEBUG_ATTN();*/ /*Mutex::Lock _l(_lock);*/ return _pico_socket_accept(s, orig, port); }
|
||||
inline int __pico_ipv6_link_add(PICO_IPV6_LINK_ADD_SIG) throw() { /*DEBUG_STACK();*/ Mutex::Lock _l(_lock); return _pico_ipv6_link_add(dev, address, netmask); }
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDK_PICOTCP
|
||||
610
src/tap.cpp
610
src/tap.cpp
@@ -1,610 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/poll.h>
|
||||
#include <stdint.h>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "tap.hpp"
|
||||
#include "sdkutils.hpp"
|
||||
#include "sdk.h"
|
||||
#include "defs.h"
|
||||
#include "debug.h"
|
||||
#include "rpc.h"
|
||||
|
||||
#if defined(SDK_LWIP)
|
||||
#include "lwip.hpp"
|
||||
#elif defined(SDK_PICOTCP)
|
||||
#include "picotcp.hpp"
|
||||
#elif defined(SDK_JIP)
|
||||
#include "jip.hpp"
|
||||
#endif
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "Constants.hpp"
|
||||
#include "Phy.hpp"
|
||||
|
||||
//#if !defined(__IOS__) && !defined(__ANDROID__) && !defined(__UNITY_3D__) && !defined(__XCODE__)
|
||||
// const ip_addr_t ip_addr_any = { IPADDR_ANY };
|
||||
//#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
int NetconEthernetTap::sendReturnValue(int fd, int retval, int _errno)
|
||||
{
|
||||
//DEBUG_INFO("fd=%d, retval=%d, errno=%d", fd, retval, _errno);
|
||||
int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
|
||||
char retmsg[sz];
|
||||
memset(&retmsg, 0, sizeof(retmsg));
|
||||
retmsg[0]=RPC_RETVAL;
|
||||
memcpy(&retmsg[1], &retval, sizeof(retval));
|
||||
memcpy(&retmsg[1]+sizeof(retval), &_errno, sizeof(_errno));
|
||||
return write(fd, &retmsg, sz);
|
||||
}
|
||||
// Unpacks the buffer from an RPC command
|
||||
void NetconEthernetTap::unloadRPC(void *data, pid_t &pid, pid_t &tid,
|
||||
char (timestamp[RPC_TIMESTAMP_SZ]), char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload)
|
||||
{
|
||||
unsigned char *buf = (unsigned char*)data;
|
||||
memcpy(&pid, &buf[IDX_PID], sizeof(pid_t));
|
||||
memcpy(&tid, &buf[IDX_TID], sizeof(pid_t));
|
||||
memcpy(timestamp, &buf[IDX_TIME], RPC_TIMESTAMP_SZ);
|
||||
memcpy(&cmd, &buf[IDX_PAYLOAD], sizeof(char));
|
||||
memcpy(CANARY, &buf[IDX_PAYLOAD+1], CANARY_SZ);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
-------------------------------- Tap Service ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
NetconEthernetTap::NetconEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,void*, uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
|
||||
void *arg) :
|
||||
_homePath(homePath),
|
||||
_mac(mac),
|
||||
_mtu(mtu),
|
||||
_nwid(nwid),
|
||||
_handler(handler),
|
||||
_arg(arg),
|
||||
_phy(this,false,true),
|
||||
_unixListenSocket((PhySocket *)0),
|
||||
_enabled(true),
|
||||
_run(true)
|
||||
{
|
||||
sockstate = -1;
|
||||
char sockPath[4096],stackPath[4096];
|
||||
Utils::snprintf(sockPath,sizeof(sockPath),"%s%snc_%.16llx",homePath,ZT_PATH_SEPARATOR_S,_nwid,ZT_PATH_SEPARATOR_S,(unsigned long long)nwid);
|
||||
_dev = sockPath; // in SDK mode, set device to be just the network ID
|
||||
|
||||
// Load and initialize network stack library
|
||||
#if defined(SDK_LWIP)
|
||||
Utils::snprintf(stackPath,sizeof(stackPath),"%s%sliblwip.so",homePath,ZT_PATH_SEPARATOR_S);
|
||||
lwipstack = new lwIP_stack(stackPath);
|
||||
if(!lwipstack) {
|
||||
DEBUG_ERROR("unable to dynamically load a new instance of (%s) (searched ZeroTier home path)", stackPath);
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
lwipstack->__lwip_init();
|
||||
DEBUG_EXTRA("network stack initialized (%p)", lwipstack);
|
||||
#elif defined(SDK_PICOTCP)
|
||||
pico_frame_rxbuf_tot = 0;
|
||||
Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibpicotcp.so",homePath,ZT_PATH_SEPARATOR_S);
|
||||
picostack = new picoTCP_stack(stackPath);
|
||||
if(!picostack) {
|
||||
DEBUG_ERROR("unable to dynamically load a new instance of (%s) (searched ZeroTier home path)", stackPath);
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
picostack->__pico_stack_init();
|
||||
DEBUG_EXTRA("network stack initialized (%p)", picostack);
|
||||
#elif defined(SDK_JIP)
|
||||
Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibjip.so",homePath,ZT_PATH_SEPARATOR_S);
|
||||
jipstack = new jip_stack(stackPath);
|
||||
#endif
|
||||
_unixListenSocket = _phy.unixListen(sockPath,(void *)this);
|
||||
|
||||
chmod(sockPath, 0777); // To make the RPC socket available to all users
|
||||
|
||||
if (!_unixListenSocket)
|
||||
DEBUG_ERROR("unable to bind to: path=%s", sockPath);
|
||||
else
|
||||
DEBUG_INFO("tap initialized on: path=%s", sockPath);
|
||||
_thread = Thread::start(this);
|
||||
}
|
||||
|
||||
NetconEthernetTap::~NetconEthernetTap()
|
||||
{
|
||||
_run = false;
|
||||
_phy.whack();
|
||||
_phy.whack(); // TODO: Rationale?
|
||||
Thread::join(_thread);
|
||||
_phy.close(_unixListenSocket,false);
|
||||
#if defined(SDK_LWIP)
|
||||
delete lwipstack;
|
||||
#endif
|
||||
#if defined(SDK_PICOTCP)
|
||||
delete picostack;
|
||||
#endif
|
||||
#if defined(SDK_JIP)
|
||||
delete jipstack;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetconEthernetTap::setEnabled(bool en)
|
||||
{
|
||||
_enabled = en;
|
||||
}
|
||||
|
||||
bool NetconEthernetTap::enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
bool NetconEthernetTap::addIp(const InetAddress &ip)
|
||||
{
|
||||
// Initialize network stack's interface, assign addresses
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_init_interface(this, ip);
|
||||
#elif defined(SDK_PICOTCP)
|
||||
picotap = this;
|
||||
pico_init_interface(this, ip);
|
||||
#elif defined(SDK_JIP)
|
||||
jip_init_interface(ip);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetconEthernetTap::removeIp(const InetAddress &ip)
|
||||
{
|
||||
Mutex::Lock _l(_ips_m);
|
||||
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
|
||||
if (i == _ips.end())
|
||||
return false;
|
||||
_ips.erase(i);
|
||||
if (ip.isV4()) {
|
||||
// TODO: De-register from network stacks
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<InetAddress> NetconEthernetTap::ips() const
|
||||
{
|
||||
Mutex::Lock _l(_ips_m);
|
||||
return _ips;
|
||||
}
|
||||
|
||||
// Receive data from ZT tap service (virtual wire) and present it to network stack
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |--------------->| | RX
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |
|
||||
// -----------------------------------------
|
||||
void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
|
||||
{
|
||||
// DEBUG_EXTRA("RX packet: len=%d, etherType=%d", len, etherType);
|
||||
// RX packet
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_rx(this, from,to,etherType,data,len);
|
||||
#elif defined(SDK_PICOTCP)
|
||||
pico_rx(this, from,to,etherType,data,len);
|
||||
#elif defined(SDK_JIP)
|
||||
jip_rx(from,to,etherType,data,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string NetconEthernetTap::deviceName() const
|
||||
{
|
||||
return _dev;
|
||||
}
|
||||
|
||||
void NetconEthernetTap::setFriendlyName(const char *friendlyName) {
|
||||
}
|
||||
|
||||
void NetconEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
|
||||
{
|
||||
std::vector<MulticastGroup> newGroups;
|
||||
Mutex::Lock _l(_multicastGroups_m);
|
||||
// TODO: get multicast subscriptions from LWIP
|
||||
std::vector<InetAddress> allIps(ips());
|
||||
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
|
||||
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
|
||||
|
||||
std::sort(newGroups.begin(),newGroups.end());
|
||||
std::unique(newGroups.begin(),newGroups.end());
|
||||
|
||||
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
|
||||
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
|
||||
added.push_back(*m);
|
||||
}
|
||||
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
|
||||
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
|
||||
removed.push_back(*m);
|
||||
}
|
||||
_multicastGroups.swap(newGroups);
|
||||
}
|
||||
|
||||
void NetconEthernetTap::threadMain()
|
||||
throw()
|
||||
{
|
||||
// Enter main thread loop for network stack
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_loop(this);
|
||||
#elif defined(SDK_PICOTCP)
|
||||
pico_loop(this);
|
||||
#elif defined(SDK_JIP)
|
||||
jip_loop(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
Connection *NetconEthernetTap::getConnection(PhySocket *sock)
|
||||
{
|
||||
for(size_t i=0;i<_Connections.size();++i) {
|
||||
if(_Connections[i]->sock == sock)
|
||||
return _Connections[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Connection *NetconEthernetTap::getConnection(struct pico_socket *sock)
|
||||
{
|
||||
for(size_t i=0;i<_Connections.size();++i) {
|
||||
if(_Connections[i]->picosock == sock)
|
||||
return _Connections[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NetconEthernetTap::closeConnection(PhySocket *sock)
|
||||
{
|
||||
Mutex::Lock _l(_close_m);
|
||||
// Here we assume _tcpconns_m is already locked by caller
|
||||
if(!sock) {
|
||||
DEBUG_EXTRA("invalid PhySocket");
|
||||
return;
|
||||
}
|
||||
// picoTCP
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleClose(sock);
|
||||
#endif
|
||||
Connection *conn = getConnection(sock);
|
||||
if(!conn)
|
||||
return;
|
||||
// lwIP
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleClose(this, sock, conn);
|
||||
#endif
|
||||
for(size_t i=0;i<_Connections.size();++i) {
|
||||
if(_Connections[i] == conn){
|
||||
_Connections.erase(_Connections.begin() + i);
|
||||
delete conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!sock)
|
||||
return;
|
||||
close(_phy.getDescriptor(sock));
|
||||
_phy.close(sock, false);
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnUnixClose(PhySocket *sock,void **uptr) {
|
||||
//DEBUG_EXTRA("physock=%p", sock);
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
//closeConnection(sock);
|
||||
}
|
||||
|
||||
|
||||
// Receive data from ZT tap service and present it to network stack
|
||||
// -----------------------------------------
|
||||
// | TAP <-> MEM BUFFER <-> STACK <-> APP |
|
||||
// | |--------------->| | RX
|
||||
// | APP <-> I/O BUFFER <-> STACK <-> TAP |
|
||||
// | |
|
||||
// -----------------------------------------
|
||||
void NetconEthernetTap::handleRead(PhySocket *sock,void **uptr,bool lwip_invoked)
|
||||
{
|
||||
// DEBUG_EXTRA("handleRead(physock=%p): lwip_invoked = %d\n", sock, lwip_invoked);
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleRead(sock, uptr, lwip_invoked);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleRead(this, sock, uptr, lwip_invoked);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked)
|
||||
{
|
||||
handleRead(sock,uptr,lwip_invoked);
|
||||
}
|
||||
|
||||
void NetconEthernetTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len)
|
||||
{
|
||||
//DEBUG_INFO("physock=%p, len=%d", sock, (int)len);
|
||||
uint64_t CANARY_num;
|
||||
pid_t pid, tid;
|
||||
ssize_t wlen = len;
|
||||
char tmpbuf[SDK_MTU];
|
||||
char cmd, timestamp[20], CANARY[CANARY_SZ], padding[] = {PADDING};
|
||||
void *payload;
|
||||
unsigned char *buf = (unsigned char*)data;
|
||||
std::pair<PhySocket*, void*> sockdata;
|
||||
PhySocket *rpcSock;
|
||||
bool foundJob = false, detected_rpc = false;
|
||||
Connection *conn;
|
||||
// RPC
|
||||
char phrase[RPC_PHRASE_SZ];
|
||||
memset(phrase, 0, RPC_PHRASE_SZ);
|
||||
if(len == BUF_SZ) {
|
||||
memcpy(phrase, buf, RPC_PHRASE_SZ);
|
||||
if(strcmp(phrase, RPC_PHRASE) == 0)
|
||||
detected_rpc = true;
|
||||
}
|
||||
if(detected_rpc) {
|
||||
unloadRPC(data, pid, tid, timestamp, CANARY, cmd, payload);
|
||||
memcpy(&CANARY_num, CANARY, CANARY_SZ);
|
||||
// DEBUG_EXTRA(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd);
|
||||
|
||||
if(cmd == RPC_SOCKET) {
|
||||
// DEBUG_INFO("RPC_SOCKET, physock=%p", sock);
|
||||
// Create new lwip socket and associate it with this sock
|
||||
struct socket_st socket_rpc;
|
||||
memcpy(&socket_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct socket_st));
|
||||
Connection * new_conn;
|
||||
if((new_conn = handleSocket(sock, uptr, &socket_rpc))) {
|
||||
new_conn->pid = pid; // Merely kept to look up application path/names later, not strictly necessary
|
||||
}
|
||||
} else {
|
||||
memcpy(&tmpbuf,data,len);
|
||||
jobmap[CANARY_num] = std::pair<PhySocket*, void*>(sock, tmpbuf);
|
||||
|
||||
}
|
||||
write(_phy.getDescriptor(sock), "z", 1); // RPC ACK byte to maintain order
|
||||
}
|
||||
// STREAM
|
||||
else {
|
||||
int data_start = -1, data_end = -1, canary_pos = -1, padding_pos = -1;
|
||||
// Look for padding
|
||||
std::string padding_pattern(padding, padding+PADDING_SZ);
|
||||
std::string buffer(buf, buf + len);
|
||||
padding_pos = buffer.find(padding_pattern);
|
||||
canary_pos = padding_pos-CANARY_SZ;
|
||||
// Grab token, next we'll use it to look up an RPC job
|
||||
if(canary_pos > -1) {
|
||||
memcpy(&CANARY_num, buf+canary_pos, CANARY_SZ);
|
||||
if(CANARY_num != 0) {
|
||||
// Find job
|
||||
sockdata = jobmap[CANARY_num];
|
||||
if(!sockdata.first) {
|
||||
return;
|
||||
} else
|
||||
foundJob = true;
|
||||
}
|
||||
}
|
||||
conn = getConnection(sock);
|
||||
if(!conn)
|
||||
return;
|
||||
|
||||
if(padding_pos == -1) { // [DATA]
|
||||
memcpy(&conn->txbuf[conn->txsz], buf, wlen);
|
||||
} else { // Padding found, implies a canary is present
|
||||
// [CANARY]
|
||||
if(len == CANARY_SZ+PADDING_SZ && canary_pos == 0) {
|
||||
wlen = 0; // Nothing to write
|
||||
} else {
|
||||
// [CANARY] + [DATA]
|
||||
if(len > CANARY_SZ+PADDING_SZ && canary_pos == 0) {
|
||||
wlen = len - CANARY_SZ+PADDING_SZ;
|
||||
data_start = padding_pos+PADDING_SZ;
|
||||
memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen);
|
||||
}
|
||||
// [DATA] + [CANARY]
|
||||
if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0 && canary_pos == len - CANARY_SZ+PADDING_SZ) {
|
||||
wlen = len - CANARY_SZ+PADDING_SZ;
|
||||
data_start = 0;
|
||||
memcpy((&conn->txbuf)+conn->txsz, buf+data_start, wlen);
|
||||
}
|
||||
// [DATA] + [CANARY] + [DATA]
|
||||
if(len > CANARY_SZ+PADDING_SZ && canary_pos > 0 && len > (canary_pos + CANARY_SZ+PADDING_SZ)) {
|
||||
wlen = len - CANARY_SZ+PADDING_SZ;
|
||||
data_start = 0;
|
||||
data_end = padding_pos-CANARY_SZ;
|
||||
memcpy((&conn->txbuf)+conn->txsz, buf+data_start, (data_end-data_start)+1);
|
||||
memcpy((&conn->txbuf)+conn->txsz, buf+(padding_pos+PADDING_SZ), len-(canary_pos+CANARY_SZ+PADDING_SZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write data from stream
|
||||
if(wlen) {
|
||||
conn->txsz += wlen;
|
||||
handleWrite(conn);
|
||||
}
|
||||
}
|
||||
// Process RPC if we have a corresponding jobmap entry
|
||||
if(foundJob) {
|
||||
rpcSock = sockdata.first;
|
||||
buf = (unsigned char*)sockdata.second;
|
||||
unloadRPC(buf, pid, tid, timestamp, CANARY, cmd, payload);
|
||||
//DEBUG_ERROR(" RPC: physock=%p, (pid=%d, tid=%d, timestamp=%s, cmd=%d)", sock, pid, tid, timestamp, cmd);
|
||||
switch(cmd) {
|
||||
case RPC_BIND:
|
||||
//DEBUG_INFO("RPC_BIND, physock=%p", sock);
|
||||
struct bind_st bind_rpc;
|
||||
memcpy(&bind_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct bind_st));
|
||||
handleBind(sock, rpcSock, uptr, &bind_rpc);
|
||||
break;
|
||||
case RPC_LISTEN:
|
||||
//DEBUG_INFO("RPC_LISTEN, physock=%p", sock);
|
||||
struct listen_st listen_rpc;
|
||||
memcpy(&listen_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct listen_st));
|
||||
handleListen(sock, rpcSock, uptr, &listen_rpc);
|
||||
break;
|
||||
case RPC_GETSOCKNAME:
|
||||
//DEBUG_INFO("RPC_GETSOCKNAME, physock=%p", sock);
|
||||
struct getsockname_st getsockname_rpc;
|
||||
memcpy(&getsockname_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st));
|
||||
handleGetsockname(sock, rpcSock, uptr, &getsockname_rpc);
|
||||
break;
|
||||
case RPC_GETPEERNAME:
|
||||
//DEBUG_INFO("RPC_GETPEERNAME, physock=%p", sock);
|
||||
struct getsockname_st getpeername_rpc;
|
||||
memcpy(&getpeername_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct getsockname_st));
|
||||
handleGetpeername(sock, rpcSock, uptr, &getpeername_rpc);
|
||||
break;
|
||||
case RPC_CONNECT:
|
||||
//DEBUG_INFO("RPC_CONNECT, physock=%p", sock);
|
||||
struct connect_st connect_rpc;
|
||||
memcpy(&connect_rpc, &buf[IDX_PAYLOAD+STRUCT_IDX], sizeof(struct connect_st));
|
||||
handleConnect(sock, rpcSock, conn, &connect_rpc);
|
||||
jobmap.erase(CANARY_num);
|
||||
return; // Keep open RPC, we'll use it once in nc_connected to send retval
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
closeConnection(sockdata.first); // close RPC after sending retval, no longer needed
|
||||
jobmap.erase(CANARY_num);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
----------------------------- RPC Handler functions ----------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
void NetconEthernetTap::handleGetsockname(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct getsockname_st *getsockname_rpc)
|
||||
{
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
Connection *conn = getConnection(sock);
|
||||
if(conn->local_addr == NULL){
|
||||
DEBUG_EXTRA("no address info available. is it bound?");
|
||||
struct sockaddr_storage storage;
|
||||
memset(&storage, 0, sizeof(struct sockaddr_storage));
|
||||
write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage));
|
||||
return;
|
||||
}
|
||||
write(_phy.getDescriptor(rpcSock), conn->local_addr, sizeof(struct sockaddr_storage));
|
||||
}
|
||||
|
||||
void NetconEthernetTap::handleGetpeername(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct getsockname_st *getsockname_rpc)
|
||||
{
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
Connection *conn = getConnection(sock);
|
||||
if(conn->peer_addr == NULL){
|
||||
DEBUG_EXTRA("no peer address info available. is it connected?");
|
||||
struct sockaddr_storage storage;
|
||||
memset(&storage, 0, sizeof(struct sockaddr_storage));
|
||||
write(_phy.getDescriptor(rpcSock), NULL, sizeof(struct sockaddr_storage));
|
||||
return;
|
||||
}
|
||||
write(_phy.getDescriptor(rpcSock), conn->peer_addr, sizeof(struct sockaddr_storage));
|
||||
}
|
||||
|
||||
Connection * NetconEthernetTap::handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc)
|
||||
{
|
||||
#if defined(SDK_PICOTCP)
|
||||
return pico_handleSocket(sock, uptr, socket_rpc);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
return lwip_handleSocket(this, sock, uptr, socket_rpc);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Connection * NetconEthernetTap::handleSocketProxy(PhySocket *sock, int socket_type)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int NetconEthernetTap::handleConnectProxy(PhySocket *sock, struct sockaddr_in *rawAddr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Connect a stack's PCB/socket/Connection object to a remote host
|
||||
void NetconEthernetTap::handleConnect(PhySocket *sock, PhySocket *rpcSock, Connection *conn, struct connect_st* connect_rpc)
|
||||
{
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleConnect(sock, rpcSock, conn, connect_rpc);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleConnect(this, sock, rpcSock, conn, connect_rpc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetconEthernetTap::handleBind(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct bind_st *bind_rpc)
|
||||
{
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
if(!_ips.size()) {
|
||||
// We haven't been given an address yet. Binding at this stage is premature
|
||||
DEBUG_ERROR("cannot bind yet. ZT address hasn't been provided");
|
||||
sendReturnValue(_phy.getDescriptor(rpcSock), -1, ENOMEM);
|
||||
return;
|
||||
}
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleBind(sock,rpcSock,uptr,bind_rpc);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleBind(this, sock, rpcSock, uptr, bind_rpc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetconEthernetTap::handleListen(PhySocket *sock, PhySocket *rpcSock, void **uptr, struct listen_st *listen_rpc)
|
||||
{
|
||||
Mutex::Lock _l(_tcpconns_m);
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleListen(sock, rpcSock, uptr, listen_rpc);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleListen(this, sock, rpcSock, uptr, listen_rpc);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write to the network stack (and thus out onto the network)
|
||||
void NetconEthernetTap::handleWrite(Connection *conn)
|
||||
{
|
||||
#if defined(SDK_PICOTCP)
|
||||
pico_handleWrite(conn);
|
||||
#endif
|
||||
#if defined(SDK_LWIP)
|
||||
lwip_handleWrite(this, conn);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
384
src/tap.hpp
384
src/tap.hpp
@@ -1,384 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_NETCONETHERNETTAP_HPP
|
||||
#define ZT_NETCONETHERNETTAP_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "Phy.hpp"
|
||||
|
||||
#include "defs.h"
|
||||
#include "rpc.h"
|
||||
|
||||
#if defined(SDK_LWIP)
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip.hpp"
|
||||
#elif defined(SDK_PICOTCP)
|
||||
#include "picotcp.hpp"
|
||||
#include "pico_protocol.h"
|
||||
#endif
|
||||
|
||||
// lwIP structs
|
||||
struct tcp_pcb;
|
||||
struct udp_pcb;
|
||||
|
||||
// ZT RPC structs
|
||||
struct socket_st;
|
||||
struct listen_st;
|
||||
struct bind_st;
|
||||
struct connect_st;
|
||||
struct getsockname_st;
|
||||
struct accept_st;
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class NetconEthernetTap;
|
||||
class LWIPStack;
|
||||
|
||||
extern struct pico_device picodev;
|
||||
extern NetconEthernetTap *picotap;
|
||||
|
||||
/*
|
||||
* TCP connection
|
||||
*/
|
||||
struct Connection
|
||||
{
|
||||
bool listening, probation, disabled;
|
||||
int pid, txsz, rxsz, type;
|
||||
PhySocket *rpcSock, *sock;
|
||||
struct tcp_pcb *TCP_pcb;
|
||||
struct udp_pcb *UDP_pcb;
|
||||
struct sockaddr_storage *local_addr; // Address we've bound to locally
|
||||
struct sockaddr_storage *peer_addr; // Address of connection call to remote host
|
||||
unsigned short port;
|
||||
unsigned char txbuf[DEFAULT_TCP_TX_BUF_SZ];
|
||||
unsigned char rxbuf[DEFAULT_TCP_RX_BUF_SZ];
|
||||
// TODO: necessary still?
|
||||
int proxy_conn_state;
|
||||
|
||||
// pico
|
||||
struct pico_socket *picosock;
|
||||
};
|
||||
|
||||
/*
|
||||
* A helper for passing a reference to _phy to LWIP callbacks as a "state"
|
||||
*/
|
||||
struct Larg
|
||||
{
|
||||
NetconEthernetTap *tap;
|
||||
Connection *conn;
|
||||
Larg(NetconEthernetTap *_tap, Connection *conn) : tap(_tap), conn(conn) {}
|
||||
};
|
||||
|
||||
/*
|
||||
* Network Containers instance -- emulates an Ethernet tap device as far as OneService knows
|
||||
*/
|
||||
class NetconEthernetTap
|
||||
{
|
||||
friend class Phy<NetconEthernetTap *>;
|
||||
|
||||
public:
|
||||
NetconEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,void*,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
|
||||
void *arg);
|
||||
|
||||
~NetconEthernetTap();
|
||||
|
||||
void setEnabled(bool en);
|
||||
bool enabled() const;
|
||||
bool addIp(const InetAddress &ip);
|
||||
bool removeIp(const InetAddress &ip);
|
||||
std::vector<InetAddress> ips() const;
|
||||
std::vector<InetAddress> _ips;
|
||||
|
||||
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
std::string deviceName() const;
|
||||
void setFriendlyName(const char *friendlyName);
|
||||
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
|
||||
|
||||
int sendReturnValue(int fd, int retval, int _errno);
|
||||
void unloadRPC(void *data, pid_t &pid, pid_t &tid, char (timestamp[RPC_TIMESTAMP_SZ]), char (CANARY[sizeof(uint64_t)]), char &cmd, void* &payload);
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
std::string _homePath;
|
||||
MAC _mac;
|
||||
unsigned int _mtu;
|
||||
uint64_t _nwid;
|
||||
void (*_handler)(void *,void*, uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
|
||||
void *_arg;
|
||||
Phy<NetconEthernetTap *> _phy;
|
||||
PhySocket *_unixListenSocket;
|
||||
volatile bool _enabled;
|
||||
volatile bool _run;
|
||||
|
||||
// --- Proxy
|
||||
struct sockaddr_storage proxyServerAddress;
|
||||
int sockstate; // Use as flag to determine whether proxy has been started, TODO: Rename
|
||||
int proxyListenSocket;
|
||||
PhySocket *proxyListenPhySocket;
|
||||
int startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr);
|
||||
int stopProxyServer();
|
||||
int getProxyServerAddress(struct sockaddr_storage *addr);
|
||||
int getProxyServerPort();
|
||||
void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable);
|
||||
// --- end Proxy
|
||||
|
||||
|
||||
// lwIP
|
||||
#if defined(SDK_LWIP)
|
||||
netif interface, interface6;
|
||||
lwIP_stack *lwipstack;
|
||||
#endif
|
||||
// jip
|
||||
#if defined(SDK_JIP)
|
||||
jip_stack *jipstack;
|
||||
#endif
|
||||
// picoTCP
|
||||
#if defined(SDK_PICOTCP)
|
||||
unsigned char pico_frame_rxbuf[MAX_PICO_FRAME_RX_BUF_SZ];
|
||||
int pico_frame_rxbuf_tot;
|
||||
Mutex _pico_frame_rxbuf_m;
|
||||
picoTCP_stack *picostack;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handles an RPC to bind an LWIP PCB to a given address and port
|
||||
*
|
||||
* @param PhySocket associated with this RPC connection
|
||||
* @param structure containing the data and parameters for this client's RPC
|
||||
*
|
||||
|
||||
i := should be implemented in intercept lib
|
||||
I := is implemented in intercept lib
|
||||
X := is implemented in service
|
||||
? := required treatment Unknown
|
||||
- := Not needed
|
||||
|
||||
[ ] EACCES - The address is protected, and the user is not the superuser.
|
||||
[X] EADDRINUSE - The given address is already in use.
|
||||
[I] EBADF - sockfd is not a valid descriptor.
|
||||
[X] EINVAL - The socket is already bound to an address.
|
||||
[I] ENOTSOCK - sockfd is a descriptor for a file, not a socket.
|
||||
|
||||
[X] ENOMEM - Insufficient kernel memory was available.
|
||||
|
||||
- The following errors are specific to UNIX domain (AF_UNIX) sockets:
|
||||
|
||||
[-] EACCES - Search permission is denied on a component of the path prefix. (See also path_resolution(7).)
|
||||
[-] EADDRNOTAVAIL - A nonexistent interface was requested or the requested address was not local.
|
||||
[-] EFAULT - addr points outside the user's accessible address space.
|
||||
[-] EINVAL - The addrlen is wrong, or the socket was not in the AF_UNIX family.
|
||||
[-] ELOOP - Too many symbolic links were encountered in resolving addr.
|
||||
[-] ENAMETOOLONG - s addr is too long.
|
||||
[-] ENOENT - The file does not exist.
|
||||
[-] ENOTDIR - A component of the path prefix is not a directory.
|
||||
[-] EROFS - The socket inode would reside on a read-only file system.
|
||||
*/
|
||||
void handleBind(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct bind_st *bind_rpc);
|
||||
|
||||
/*
|
||||
* Handles an RPC to put an LWIP PCB into LISTEN mode
|
||||
*
|
||||
* @param PhySocket associated with this RPC connection
|
||||
* @param structure containing the data and parameters for this client's RPC
|
||||
*
|
||||
|
||||
i := should be implemented in intercept lib
|
||||
I := is implemented in intercept lib
|
||||
X := is implemented in service
|
||||
? := required treatment Unknown
|
||||
- := Not needed
|
||||
|
||||
[?] EADDRINUSE - Another socket is already listening on the same port.
|
||||
[IX] EBADF - The argument sockfd is not a valid descriptor.
|
||||
[I] ENOTSOCK - The argument sockfd is not a socket.
|
||||
[I] EOPNOTSUPP - The socket is not of a type that supports the listen() operation.
|
||||
*/
|
||||
void handleListen(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct listen_st *listen_rpc);
|
||||
|
||||
/*
|
||||
* Handles an RPC to create a socket (LWIP PCB and associated socketpair)
|
||||
*
|
||||
* A socketpair is created, one end is kept and wrapped into a PhySocket object
|
||||
* for use in the main ZT I/O loop, and one end is sent to the client. The client
|
||||
* is then required to tell the service what new file descriptor it has allocated
|
||||
* for this connection. After the mapping is complete, the socket can be used.
|
||||
*
|
||||
* @param PhySocket associated with this RPC connection
|
||||
* @param structure containing the data and parameters for this client's RPC
|
||||
*
|
||||
|
||||
i := should be implemented in intercept lib
|
||||
I := is implemented in intercept lib
|
||||
X := is implemented in service
|
||||
? := required treatment Unknown
|
||||
- := Not needed
|
||||
|
||||
[-] EACCES - Permission to create a socket of the specified type and/or protocol is denied.
|
||||
[I] EAFNOSUPPORT - The implementation does not support the specified address family.
|
||||
[I] EINVAL - Unknown protocol, or protocol family not available.
|
||||
[I] EINVAL - Invalid flags in type.
|
||||
[I] EMFILE - Process file table overflow.
|
||||
[?] ENFILE - The system limit on the total number of open files has been reached.
|
||||
[X] ENOBUFS or ENOMEM - Insufficient memory is available. The socket cannot be created until sufficient resources are freed.
|
||||
[?] EPROTONOSUPPORT - The protocol type or the specified protocol is not supported within this domain.
|
||||
*/
|
||||
Connection * handleSocket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
|
||||
Connection * handleSocketProxy(PhySocket *sock, int socket_type);
|
||||
|
||||
/*
|
||||
* Handles an RPC to connect to a given address and port
|
||||
*
|
||||
* @param PhySocket associated with this RPC connection
|
||||
* @param structure containing the data and parameters for this client's RPC
|
||||
|
||||
--- Error handling in this method will only catch problems which are immedately
|
||||
apprent. Some errors will need to be caught in the nc_connected(0 callback
|
||||
|
||||
i := should be implemented in intercept lib
|
||||
I := is implemented in intercept lib
|
||||
X := is implemented in service
|
||||
? := required treatment Unknown
|
||||
- := Not needed
|
||||
|
||||
[-] EACCES - For UNIX domain sockets, which are identified by pathname: Write permission is denied ...
|
||||
[?] EACCES, EPERM - The user tried to connect to a broadcast address without having the socket broadcast flag enabled ...
|
||||
[X] EADDRINUSE - Local address is already in use.
|
||||
[I] EAFNOSUPPORT - The passed address didn't have the correct address family in its sa_family field.
|
||||
[X] EAGAIN - No more free local ports or insufficient entries in the routing cache.
|
||||
[ ] EALREADY - The socket is nonblocking and a previous connection attempt has not yet been completed.
|
||||
[IX] EBADF - The file descriptor is not a valid index in the descriptor table.
|
||||
[ ] ECONNREFUSED - No-one listening on the remote address.
|
||||
[i] EFAULT - The socket structure address is outside the user's address space.
|
||||
[ ] EINPROGRESS - The socket is nonblocking and the connection cannot be completed immediately.
|
||||
[-] EINTR - The system call was interrupted by a signal that was caught.
|
||||
[X] EISCONN - The socket is already connected.
|
||||
[X] ENETUNREACH - Network is unreachable.
|
||||
[I] ENOTSOCK - The file descriptor is not associated with a socket.
|
||||
[X] ETIMEDOUT - Timeout while attempting connection.
|
||||
|
||||
[X] EINVAL - Invalid argument, SVr4, generally makes sense to set this
|
||||
*/
|
||||
void handleConnect(PhySocket *sock, PhySocket *rpcsock, Connection *conn, struct connect_st* connect_rpc);
|
||||
int handleConnectProxy(PhySocket *sock, struct sockaddr_in *rawAddr);
|
||||
|
||||
// void handleIsConnected();
|
||||
|
||||
/*
|
||||
* Return the address that the socket is bound to
|
||||
*/
|
||||
void handleGetsockname(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
|
||||
|
||||
/*
|
||||
* Return the address of the peer connected to this socket
|
||||
*/
|
||||
void handleGetpeername(PhySocket *sock, PhySocket *rpcsock, void **uptr, struct getsockname_st *getsockname_rpc);
|
||||
|
||||
/*
|
||||
* Writes data from the application's socket to the LWIP connection
|
||||
*/
|
||||
void handleWrite(Connection *conn);
|
||||
|
||||
// Unused -- no UDP or TCP from this thread/Phy<>
|
||||
void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, const struct sockaddr *from,void *data,unsigned long len);
|
||||
void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success);
|
||||
void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from);
|
||||
void phyOnTcpClose(PhySocket *sock,void **uptr);
|
||||
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len);
|
||||
|
||||
void handleRead(PhySocket *sock,void **uptr,bool lwip_invoked);
|
||||
void phyOnTcpWritable(PhySocket *sock,void **uptr, bool lwip_invoked);
|
||||
|
||||
/*
|
||||
* Signals us to close the TcpConnection associated with this PhySocket
|
||||
*/
|
||||
void phyOnUnixClose(PhySocket *sock,void **uptr);
|
||||
|
||||
/*
|
||||
* Notifies us that there is data to be read from an application's socket
|
||||
*/
|
||||
void phyOnUnixData(PhySocket *sock,void **uptr,void *data,ssize_t len);
|
||||
|
||||
/*
|
||||
* Notifies us that we can write to an application's socket
|
||||
*/
|
||||
void phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_invoked);
|
||||
|
||||
/*
|
||||
* Returns a pointer to a TcpConnection associated with a given PhySocket
|
||||
*/
|
||||
Connection *getConnection(PhySocket *sock);
|
||||
|
||||
/*
|
||||
* Returns a pointer to a TcpConnection associated with a given pico_socket
|
||||
*/
|
||||
Connection *getConnection(struct pico_socket *socket);
|
||||
|
||||
/*
|
||||
* Closes a TcpConnection, associated LWIP PCB strcuture,
|
||||
* PhySocket, and underlying file descriptor
|
||||
*/
|
||||
void closeConnection(PhySocket *sock);
|
||||
|
||||
std::vector<Connection*> _Connections;
|
||||
|
||||
std::map<uint64_t, std::pair<PhySocket*, void*> > jobmap;
|
||||
pid_t rpcCounter;
|
||||
|
||||
Thread _thread;
|
||||
std::string _dev; // path to Unix domain socket
|
||||
|
||||
std::vector<MulticastGroup> _multicastGroups;
|
||||
Mutex _multicastGroups_m;
|
||||
|
||||
Mutex _ips_m, _tcpconns_m, _rx_buf_m, _close_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
@@ -1,3 +0,0 @@
|
||||
Language/Framework Wrappers
|
||||
====
|
||||
These wrappers are designed to abstract the ZeroTierSDK Sockets API (implemented in `src/sockets.c`) to your native language of choice. Specific examples of how to use these are located in the `integrations` directory..
|
||||
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
// TODO:
|
||||
/*
|
||||
* check for mem leaks surrounding managed/unmanaged barrier
|
||||
* find root of 2X buffer size requirement issue
|
||||
* check that cross-thread oprations are handled correctly
|
||||
* check that .IsRunning() doesn't bork the entire system anymore
|
||||
* Allow max packet size configuration
|
||||
* Handle exceptions from unmanaged code
|
||||
* */
|
||||
|
||||
// Provides a bare-bones interface to ZeroTier-administered sockets
|
||||
public class ZTSDK {
|
||||
|
||||
// ZeroTier background thread
|
||||
protected Thread ztThread;
|
||||
protected List<int> connections = new List<int> ();
|
||||
protected int MaxPacketSize;
|
||||
|
||||
// Only allow one network at a time for BETA
|
||||
protected bool joined_to_network = false;
|
||||
protected string nwid = "";
|
||||
protected string path = "";
|
||||
|
||||
// Platform-specific paths and bundle/libary names
|
||||
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
||||
const string DLL_PATH = "ZeroTierSDK_Unity3D_OSX";
|
||||
protected string rpc_path = "/Library/Application\\ Support/ZeroTier/SDK/";
|
||||
#endif
|
||||
#if UNITY_IOS || UNITY_IPHONE
|
||||
const string DLL_PATH = "ZeroTierSDK_Unity3D_iOS";
|
||||
protected string rpc_path = "ZeroTier/One/";
|
||||
#endif
|
||||
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
||||
const string DLL_PATH = "ZeroTierSDK_Unity3D_WIN";
|
||||
protected string rpc_path = "";
|
||||
#endif
|
||||
#if UNITY_STANDALONE_LINUX
|
||||
const string DLL_PATH = "ZeroTierSDK_Unity3D_LINUX";
|
||||
protected string rpc_path = "";
|
||||
#endif
|
||||
#if UNITY_ANDROID
|
||||
const string DLL_PATH = "ZeroTierSDK_Unity3D_ANDROID";
|
||||
protected string rpc_path = "ZeroTier/One/";
|
||||
#endif
|
||||
|
||||
#region DLL Imports
|
||||
// ZeroTier service / debug initialization
|
||||
[DllImport (DLL_PATH)]
|
||||
public static extern void SetDebugFunction( IntPtr fp );
|
||||
[DllImport (DLL_PATH)]
|
||||
private static extern int unity_start_service(string path);
|
||||
[DllImport (DLL_PATH)]
|
||||
private static extern int unity_start_service_and_rpc(string path, string nwid);
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern bool zts_is_running();
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern void zts_stop_service();
|
||||
|
||||
// Connection calls
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern int zts_socket(int family, int type, int protocol);
|
||||
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_bind(int sockfd, System.IntPtr addr, int addrlen);
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_connect(int sockfd, System.IntPtr addr, int addrlen);
|
||||
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern int zts_accept(int sockfd);
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern int zts_listen(int sockfd, int backlog);
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern int zts_close(int sockfd);
|
||||
|
||||
// RX / TX
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_recv(int sockfd, [In, Out] IntPtr buf, int len);
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_send(int sockfd, IntPtr buf, int len);
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_set_nonblock(int sockfd);
|
||||
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_sendto(int fd, IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen);
|
||||
[DllImport (DLL_PATH)]
|
||||
unsafe protected static extern int zts_recvfrom(int fd, [In, Out] IntPtr buf, int len, int flags, System.IntPtr addr, int addrlen);
|
||||
|
||||
// ZT Network controls
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern void zts_join_network(string nwid);
|
||||
[DllImport (DLL_PATH)]
|
||||
protected static extern void zts_leave_network(string nwid);
|
||||
#endregion
|
||||
|
||||
// Interop structures
|
||||
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
|
||||
public struct sockaddr {
|
||||
/// u_short->unsigned short
|
||||
public ushort sa_family;
|
||||
/// char[14]
|
||||
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=14)]
|
||||
public string sa_data;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void MyDelegate(string str);
|
||||
|
||||
// Debug output callback
|
||||
static void CallBackFunction(string str) {
|
||||
Debug.Log("ZeroTier: " + str);
|
||||
}
|
||||
|
||||
|
||||
// Returns a path for RPC communications to the service
|
||||
private string rpcCommPath()
|
||||
{
|
||||
if(path != "" && nwid != "") {
|
||||
return path + "nc_" + nwid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Thread which starts the ZeroTier service
|
||||
protected void zt_service_thread()
|
||||
{
|
||||
// Set up debug callback
|
||||
MyDelegate callback_delegate = new MyDelegate( CallBackFunction );
|
||||
IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate);
|
||||
SetDebugFunction( intptr_delegate );
|
||||
|
||||
// Start service
|
||||
/* This new instance will communicate via a named pipe, so any
|
||||
* API calls (ZeroTier.Connect(), ZeroTier.Send(), etc) will be sent to the service
|
||||
* via this pipe.
|
||||
*/
|
||||
if(nwid.Length > 0) {
|
||||
unity_start_service_and_rpc (path, nwid);
|
||||
}
|
||||
else {
|
||||
unity_start_service(rpcCommPath());
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the nwid of the network you're currently connected to
|
||||
public string GetNetworkID() {
|
||||
return nwid;
|
||||
}
|
||||
|
||||
// Returns whether you're currently connected to a network
|
||||
public bool IsConnected() {
|
||||
return nwid != "";
|
||||
}
|
||||
|
||||
// Start the ZeroTier service
|
||||
protected void Init()
|
||||
{
|
||||
ztThread = new Thread(() => {
|
||||
try {
|
||||
zt_service_thread();
|
||||
} catch(Exception e) {
|
||||
Debug.Log(e.Message.ToString());
|
||||
}
|
||||
});
|
||||
ztThread.IsBackground = true; // Allow the thread to be aborted safely
|
||||
ztThread.Start();
|
||||
}
|
||||
|
||||
// Initialize the ZeroTier service with a given path
|
||||
public ZTSDK(string path, string nwid) {
|
||||
Debug.Log("ZTSDK(): " + nwid);
|
||||
|
||||
this.path = path;
|
||||
this.nwid = nwid;
|
||||
Init();
|
||||
}
|
||||
|
||||
public ZTSDK (string path) {
|
||||
this.path = path;
|
||||
Init();
|
||||
}
|
||||
|
||||
// Initialize the ZeroTier service
|
||||
public ZTSDK() {
|
||||
Init();
|
||||
}
|
||||
|
||||
#region Network Handling
|
||||
// Joins a ZeroTier virtual network
|
||||
public bool JoinNetwork(string nwid)
|
||||
{
|
||||
if(!joined_to_network) {
|
||||
zts_join_network(nwid);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Leaves a ZeroTier virtual network
|
||||
public bool LeaveNetwork(string nwid)
|
||||
{
|
||||
if(!joined_to_network) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
zts_leave_network(nwid);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// Creates a new ZeroTier-administered socket
|
||||
public int Socket(int family, int type, int protocol)
|
||||
{
|
||||
return zts_socket (family, type, protocol);
|
||||
}
|
||||
|
||||
// Binds to a specific address
|
||||
public int Bind(int fd, string addr, int port)
|
||||
{
|
||||
GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port);
|
||||
IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject ();
|
||||
int addrlen = Marshal.SizeOf (pSockAddr);
|
||||
return zts_bind (fd, pSockAddr, addrlen);
|
||||
}
|
||||
|
||||
// Listens for an incoming connection request
|
||||
public int Listen(int fd, int backlog)
|
||||
{
|
||||
return zts_listen(fd, backlog);
|
||||
}
|
||||
|
||||
// Accepts an incoming connection
|
||||
public int Accept(int fd)
|
||||
{
|
||||
return zts_accept (fd);
|
||||
}
|
||||
|
||||
// Closes a connection
|
||||
public int Close(int fd)
|
||||
{
|
||||
return Close (fd);
|
||||
}
|
||||
|
||||
// Connects to a remote host
|
||||
public int Connect(int fd, string addr, int port)
|
||||
{
|
||||
GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port);
|
||||
IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject ();
|
||||
int addrlen = Marshal.SizeOf (pSockAddr);
|
||||
return zts_connect (fd, pSockAddr, addrlen);
|
||||
}
|
||||
|
||||
public int Read(int fd, ref char[] buf, int len)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
IntPtr ptr = handle.AddrOfPinnedObject();
|
||||
int bytes_read = zts_recv (fd, ptr, len*2);
|
||||
string str = Marshal.PtrToStringAuto(ptr);
|
||||
//Marshal.Copy (ptr, buf, 0, bytes_read);
|
||||
buf = Marshal.PtrToStringAnsi(ptr).ToCharArray();
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
public int Write(int fd, char[] buf, int len)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
IntPtr ptr = handle.AddrOfPinnedObject();
|
||||
//error = 0;
|
||||
int bytes_written;
|
||||
// FIXME: Sending a length of 2X the buffer size seems to fix the object pinning issue
|
||||
if((bytes_written = zts_send(fd, ptr, len*2)) < 0) {
|
||||
//error = (byte)bytes_written;
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
// Sends data to an address
|
||||
public int SendTo(int fd, char[] buf, int len, int flags, string addr, int port)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
IntPtr ptr = handle.AddrOfPinnedObject();
|
||||
int bytes_written;
|
||||
|
||||
// Form address structure
|
||||
GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port);
|
||||
IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject ();
|
||||
int addrlen = Marshal.SizeOf (pSockAddr);
|
||||
|
||||
if((bytes_written = zts_sendto(fd, ptr, len*2, flags, pSockAddr, addrlen)) < 0) {
|
||||
//error = (byte)bytes_written;
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
// Receives data from an address
|
||||
public int RecvFrom(int fd, ref char[] buf, int len, int flags, string addr, int port)
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
IntPtr ptr = handle.AddrOfPinnedObject();
|
||||
|
||||
// Form address structure
|
||||
GCHandle sockaddr_ptr = Generate_unmananged_sockaddr(addr + ":" + port);
|
||||
IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject ();
|
||||
int addrlen = Marshal.SizeOf (pSockAddr);
|
||||
|
||||
int bytes_read = zts_recvfrom(fd, ptr, len*2, flags, pSockAddr, addrlen);
|
||||
string str = Marshal.PtrToStringAuto(ptr);
|
||||
//Marshal.Copy (ptr, buf, 0, bytes_read);
|
||||
buf = Marshal.PtrToStringAnsi(ptr).ToCharArray();
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
#region Service-Related calls
|
||||
// Returns whether the ZeroTier service is currently running
|
||||
public bool IsRunning()
|
||||
{
|
||||
return zts_is_running ();
|
||||
}
|
||||
|
||||
// Terminates the ZeroTier service
|
||||
public void Terminate()
|
||||
{
|
||||
zts_stop_service ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
// --- Utilities ---
|
||||
|
||||
|
||||
// Handles IPv4 and IPv6 notation.
|
||||
public static IPEndPoint CreateIPEndPoint(string endPoint)
|
||||
{
|
||||
string[] ep = endPoint.Split(':');
|
||||
if (ep.Length < 2) throw new FormatException("Invalid endpoint format");
|
||||
IPAddress ip;
|
||||
if (ep.Length > 2) {
|
||||
if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip)) {
|
||||
throw new FormatException("Invalid ip-adress");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!IPAddress.TryParse(ep[0], out ip)) {
|
||||
throw new FormatException("Invalid ip-adress");
|
||||
}
|
||||
}
|
||||
int port;
|
||||
if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) {
|
||||
throw new FormatException("Invalid port");
|
||||
}
|
||||
return new IPEndPoint(ip, port);
|
||||
}
|
||||
|
||||
// Generates an unmanaged sockaddr structure from a string-formatted endpoint
|
||||
public static GCHandle Generate_unmananged_sockaddr(string endpoint_str)
|
||||
{
|
||||
IPEndPoint ipEndPoint;
|
||||
ipEndPoint = CreateIPEndPoint (endpoint_str);
|
||||
SocketAddress socketAddress = ipEndPoint.Serialize ();
|
||||
|
||||
// use an array of bytes instead of the sockaddr structure
|
||||
byte[] sockAddrStructureBytes = new byte[socketAddress.Size];
|
||||
GCHandle sockAddrHandle = GCHandle.Alloc (sockAddrStructureBytes, GCHandleType.Pinned);
|
||||
for (int i = 0; i < socketAddress.Size; ++i) {
|
||||
sockAddrStructureBytes [i] = socketAddress [i];
|
||||
}
|
||||
return sockAddrHandle;
|
||||
}
|
||||
|
||||
public static GCHandle Generate_unmanaged_buffer(byte[] buf)
|
||||
{
|
||||
// use an array of bytes instead of the sockaddr structure
|
||||
GCHandle sockAddrHandle = GCHandle.Alloc (buf, GCHandleType.Pinned);
|
||||
return sockAddrHandle;
|
||||
}
|
||||
}
|
||||
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package ZeroTier;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.ZipError;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
public class ZTSDK {
|
||||
|
||||
// Socket families
|
||||
public static int AF_UNIX = 1;
|
||||
public static int AF_INET = 2;
|
||||
|
||||
// Socket types
|
||||
public static int SOCK_STREAM = 1;
|
||||
public static int SOCK_DGRAM = 2;
|
||||
|
||||
// fcntl flags
|
||||
public static int O_APPEND = 1024;
|
||||
public static int O_NONBLOCK = 2048;
|
||||
public static int O_ASYNC = 8192;
|
||||
public static int O_DIRECT = 65536;
|
||||
public static int O_NOATIME = 262144;
|
||||
|
||||
// fcntl cmds
|
||||
public static int F_GETFL = 3;
|
||||
public static int F_SETFL = 4;
|
||||
|
||||
// Loads JNI code
|
||||
static { System.loadLibrary("ZeroTierOneJNI"); }
|
||||
|
||||
// ZeroTier service controls
|
||||
public native void zt_start_service(String homeDir);
|
||||
public void start_service(String homeDir) {
|
||||
zt_start_service(homeDir);
|
||||
}
|
||||
|
||||
public native void zt_join_network(String nwid);
|
||||
public void join_network(String nwid) {
|
||||
zt_join_network(nwid);
|
||||
}
|
||||
|
||||
public native void zt_leave_network(String nwid);
|
||||
public void leave_network(String nwid) {
|
||||
zt_leave_network(nwid);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------- get_addresses() ------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native ArrayList<String> zt_get_addresses(String nwid);
|
||||
public ArrayList<String> get_addresses(String nwid) {
|
||||
int err = -1;
|
||||
ArrayList<String> addresses;
|
||||
while (err < 0) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
addresses = zt_get_addresses(nwid);
|
||||
if (addresses.size() > 0) {
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public native int zt_get_proxy_port(String nwid);
|
||||
public int get_proxy_port(String nwid) {
|
||||
return zt_get_proxy_port(nwid);
|
||||
}
|
||||
|
||||
public native boolean zt_service_is_running();
|
||||
public boolean service_is_running() {
|
||||
return zt_service_is_running();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- socket() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_socket(int family, int type, int protocol);
|
||||
public int socket(int family, int type, int protocol) {
|
||||
return zt_socket(family, type, protocol);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- connect() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_connect(int fd, String addr, int port);
|
||||
|
||||
public int connect(int sock, ZTAddress zaddr, String nwid) {
|
||||
return connect(sock, zaddr.Address(), zaddr.Port(), nwid);
|
||||
}
|
||||
|
||||
public int connect(int sock, String addr, int port, String nwid)
|
||||
{
|
||||
int err = -1;
|
||||
ArrayList<String> addresses;
|
||||
while (err < 0) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
addresses = zt_get_addresses(nwid);
|
||||
if (addresses.size() > 0) {
|
||||
if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) {
|
||||
err = zt_connect(sock, addr, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ bind() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_bind(int fd, String addr, int port);
|
||||
|
||||
public int bind(int sock, ZTAddress zaddr, String nwid) {
|
||||
return bind(sock, zaddr.Address(), zaddr.Port(), nwid);
|
||||
}
|
||||
public int bind(int sock, String addr, int port, String nwid) {
|
||||
int err = -1;
|
||||
ArrayList<String> addresses;
|
||||
while (err < 0) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
addresses = zt_get_addresses(nwid);
|
||||
if (addresses.size() > 0) {
|
||||
if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) {
|
||||
err = zt_bind(sock, addr, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- accept4() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_accept4(int fd, String addr, int port);
|
||||
public int accept4(int fd, String addr, int port) {
|
||||
return zt_accept4(fd,addr,port);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- accept() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_accept(int fd, ZeroTier.ZTAddress addr);
|
||||
public int accept(int fd, ZeroTier.ZTAddress addr) {
|
||||
return zt_accept(fd, addr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- listen() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_listen(int fd, int backlog);
|
||||
public int listen(int fd, int backlog) {
|
||||
return zt_listen(fd,backlog);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- close() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_close(int fd);
|
||||
public int close(int fd) {
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ------------------------------------ read() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_read(int fd, byte[] buf, int len);
|
||||
public int read(int fd, byte[] buf, int len) {
|
||||
return zt_read(fd, buf, len);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- write() ----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_write(int fd, byte[] buf, int len);
|
||||
public int write(int fd, byte[] buf, int len) {
|
||||
return zt_write(fd, buf, len);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- sendto() ---------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr);
|
||||
public int sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){
|
||||
return zt_sendto(fd,buf,len,flags,addr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ----------------------------------- send() -----------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_send(int fd, byte[] buf, int len, int flags);
|
||||
public int send(int fd, byte[] buf, int len, int flags) {
|
||||
return zt_send(fd, buf, len, flags);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- recvfrom() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr);
|
||||
public int recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){
|
||||
return zt_recvfrom(fd,buf,len,flags,addr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// ---------------------------------- recvfrom() --------------------------------
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
public native int zt_fcntl(int sock, int cmd, int flag);
|
||||
public int fcntl(int sock, int cmd, int flag) {
|
||||
return zt_fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public static native int zt_getsockopt(int fd, int type, int protocol);
|
||||
//public static native int zt_setsockopt(int fd, int type, int protocol);
|
||||
//public static native int zt_getsockname(int fd, int type, int protocol);
|
||||
|
||||
|
||||
// PROXY SERVER CONTROLS
|
||||
public native boolean zt_proxy_is_running();
|
||||
public boolean proxy_is_running() {
|
||||
return zt_proxy_is_running();
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package ZeroTier;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// A convenience object for moving address information across the JNI memory border.
|
||||
|
||||
public class ZTAddress
|
||||
{
|
||||
// int -> byte array
|
||||
static public byte[] toIPByteArray(long addr){
|
||||
return new byte[]{(byte)addr,(byte)(addr>>>8),(byte)(addr>>>16),(byte)(addr>>>24)};
|
||||
}
|
||||
|
||||
// byte array -> int
|
||||
long toIPInt(String _addr) {
|
||||
long result = 0;
|
||||
for(String part: _addr.split(Pattern.quote("."))) {
|
||||
result = result << 8;
|
||||
result |= Integer.parseInt(part);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int port;
|
||||
public int Port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public long _rawAddr;
|
||||
public String Address()
|
||||
{
|
||||
try {
|
||||
return InetAddress.getByAddress(toIPByteArray(_rawAddr)).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
// should never happen
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Address() + ":" + Port();
|
||||
}
|
||||
|
||||
public ZTAddress()
|
||||
{
|
||||
port = -1;
|
||||
_rawAddr = -1;
|
||||
}
|
||||
|
||||
public ZTAddress(String _addr, int _port)
|
||||
{
|
||||
_rawAddr = toIPInt(_addr);
|
||||
port = _port;
|
||||
}
|
||||
|
||||
public void ZTAddress(InetSocketAddress ins)
|
||||
{
|
||||
port = ins.getPort();
|
||||
_rawAddr = toIPInt(ins.getAddress().getHostAddress());
|
||||
}
|
||||
|
||||
public InetSocketAddress ToInetSocketAddress() throws IllegalArgumentException {
|
||||
InetSocketAddress sock_addr = null;
|
||||
try {
|
||||
sock_addr = new InetSocketAddress(Address(), port);
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return sock_addr;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return port != -1 && !Address().startsWith("-1.-1.-1.-1/-1");
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//
|
||||
// Implementations located in src/wrappers/swift/XcodeWrapper.cpp
|
||||
//
|
||||
|
||||
#ifndef Example_OSX_IOS_Bridging_Header_h
|
||||
#define Example_OSX_IOS_Bridging_Header_h
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
// ZT INTERCEPT/RPC CONTROLS
|
||||
int zt_init_rpc(const char *path, const char *nwid);
|
||||
int zt_start_intercept();
|
||||
void zt_disable_intercept();
|
||||
void zt_enable_intercept();
|
||||
|
||||
// ZT SERVICE CONTROLS
|
||||
void zt_start_service(const char * path);
|
||||
void zt_stop_service();
|
||||
void zt_start_service_and_rpc(const char * path, const char * nwid);
|
||||
bool zt_service_is_running();
|
||||
void zt_join_network(const char *nwid);
|
||||
void zt_leave_network(const char *nwid);
|
||||
void zt_get_ipv4_address(const char *nwid, char *addrstr);
|
||||
void zt_get_ipv6_address(const char *nwid, char *addrstr);
|
||||
|
||||
|
||||
// SOCKS5 PROXY CONTROLS
|
||||
void zt_start_proxy_server(const char *nwid, struct sockaddr_storage addr);
|
||||
void zt_stop_proxy_server(const char *nwid);
|
||||
void zt_proxy_is_running(const char *nwid);
|
||||
void zt_get_proxy_server_address(const char *nwid, struct sockaddr_storage addr);
|
||||
|
||||
// SOCKET API
|
||||
int zt_connect(CONNECT_SIG);
|
||||
int zt_bind(BIND_SIG);
|
||||
int zt_accept(ACCEPT_SIG);
|
||||
int zt_listen(LISTEN_SIG);
|
||||
int zt_socket(SOCKET_SIG);
|
||||
int zt_setsockopt(SETSOCKOPT_SIG);
|
||||
int zt_getsockopt(GETSOCKOPT_SIG);
|
||||
int zt_close(CLOSE_SIG);
|
||||
int zt_getsockname(GETSOCKNAME_SIG);
|
||||
int zt_getpeername(GETPEERNAME_SIG);
|
||||
int zt_recvfrom(RECVFROM_SIG);
|
||||
int zt_fcntl(FCNTL_SIG);
|
||||
int zt_sendto(SENDTO_SIG);
|
||||
|
||||
#endif /* Example_OSX_IOS_Bridging_Header_h */
|
||||
|
||||
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include "sdk.h"
|
||||
#include "XcodeWrapper.hpp"
|
||||
|
||||
#define INTERCEPT_ENABLED 111
|
||||
#define INTERCEPT_DISABLED 222
|
||||
|
||||
// ZEROTIER CONTROLS
|
||||
// Starts a ZeroTier service at the specified path
|
||||
extern "C" void zt_start_service(const char *path, const char *nwid) {
|
||||
zts_start_service(path);
|
||||
//init_service(INTERCEPT_DISABLED, path);
|
||||
}
|
||||
|
||||
// Starts a ZeroTier service at the specified path and initializes the RPC mechanism
|
||||
//extern "C" void zt_start_service_and_rpc(const char *path, const char *nwid) {
|
||||
// init_service_and_rpc(INTERCEPT_DISABLED, path, nwid);
|
||||
//}
|
||||
|
||||
// Stops the core ZeroTier service
|
||||
extern "C" void zt_stop_service() {
|
||||
zts_stop_service();
|
||||
}
|
||||
// Returns whether the core ZeroTier service is running
|
||||
extern "C" bool zt_service_is_running() {
|
||||
return zts_service_is_running();
|
||||
}
|
||||
// Joins a ZeroTier virtual network
|
||||
extern "C" void zt_join_network(const char *nwid) {
|
||||
zts_join_network(nwid);
|
||||
}
|
||||
// Leaves a ZeroTier virtual network
|
||||
extern "C" void zt_leave_network(const char *nwid) {
|
||||
zts_leave_network(nwid);
|
||||
}
|
||||
// Returns a list of addresses associated with this device on the given network
|
||||
extern "C" void zt_get_ipv4_address(const char *nwid, char *addrstr) {
|
||||
zts_get_ipv4_address(nwid, addrstr);
|
||||
}
|
||||
// Returns a list of addresses associated with this device on the given network
|
||||
extern "C" void zt_get_ipv6_address(const char *nwid, char *addrstr) {
|
||||
zts_get_ipv6_address(nwid, addrstr);
|
||||
}
|
||||
|
||||
|
||||
// PROXY SERVER CONTROLS
|
||||
//
|
||||
extern "C" void zt_start_proxy_server(const char *homepath, const char *nwid, struct sockaddr_storage *addr) {
|
||||
zts_start_proxy_server(homepath, nwid, addr);
|
||||
}
|
||||
//
|
||||
extern "C" void zt_stop_proxy_server(const char *nwid) {
|
||||
zts_stop_proxy_server(nwid);
|
||||
}
|
||||
//
|
||||
extern "C" void zt_proxy_is_running(const char *nwid) {
|
||||
zts_proxy_is_running(nwid);
|
||||
}
|
||||
//
|
||||
extern "C" void zt_get_proxy_server_address(const char *nwid, struct sockaddr_storage *addr) {
|
||||
zts_get_proxy_server_address(nwid, addr);
|
||||
}
|
||||
// Explicit ZT API wrappers
|
||||
#if !defined(__IOS__)
|
||||
// This isn't available for iOS since function interposition isn't as reliable
|
||||
extern "C" void zt_init_rpc(const char *path, const char *nwid) {
|
||||
zts_init_rpc(path, nwid);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// SOCKET API
|
||||
// These are used in ZTSDK.swift to implement the higher-level API
|
||||
extern "C" int zt_socket(SOCKET_SIG) {
|
||||
return zts_socket(socket_family, socket_type, protocol);
|
||||
}
|
||||
extern "C" int zt_connect(CONNECT_SIG) {
|
||||
return zts_connect(fd, addr, addrlen);
|
||||
}
|
||||
extern "C" int zt_bind(BIND_SIG){
|
||||
return zts_bind(fd, addr, addrlen);
|
||||
}
|
||||
extern "C" int zt_accept(ACCEPT_SIG) {
|
||||
return zts_accept(fd, addr, addrlen);
|
||||
}
|
||||
extern "C" int zt_listen(LISTEN_SIG) {
|
||||
return zts_listen(fd, backlog);
|
||||
}
|
||||
extern "C" int zt_setsockopt(SETSOCKOPT_SIG) {
|
||||
return zts_setsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
extern "C" int zt_getsockopt(GETSOCKOPT_SIG) {
|
||||
return zts_getsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
extern "C" int zt_close(CLOSE_SIG) {
|
||||
return zts_close(fd);
|
||||
}
|
||||
extern "C" int zt_getsockname(GETSOCKNAME_SIG) {
|
||||
return zts_getsockname(fd, addr, addrlen);
|
||||
}
|
||||
extern "C" int zt_getpeername(GETPEERNAME_SIG) {
|
||||
return zts_getpeername(fd, addr, addrlen);
|
||||
}
|
||||
extern "C" int zt_fcntl(FCNTL_SIG) {
|
||||
return zts_fcntl(fd, cmd, flags);
|
||||
}
|
||||
extern "C" ssize_t zt_recvfrom(RECVFROM_SIG) {
|
||||
return zts_recvfrom(fd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
extern "C" ssize_t zt_sendto(SENDTO_SIG) {
|
||||
return zts_sendto(fd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef SDK_XCODE_WRAPPER_HPP
|
||||
#define SDK_XCODE_WRAPPER_HPP
|
||||
|
||||
#endif // SDK_XCODE_WRAPPER_HPP
|
||||
@@ -1,198 +0,0 @@
|
||||
//
|
||||
// ZTSDK.swift
|
||||
// Example_iOS_App
|
||||
//
|
||||
// Created by Joseph Henry on 9/7/16.
|
||||
// Copyright © 2016 ZeroTier Inc. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// Convenience structure for getting address data to/from the native library
|
||||
struct ZTAddress
|
||||
{
|
||||
var family: Int32
|
||||
var addr: String
|
||||
var port: Int16
|
||||
var data: sockaddr_in?
|
||||
|
||||
init(_ family: Int32, _ addr: String, _ port: Int16) {
|
||||
self.family = family
|
||||
self.addr = addr
|
||||
self.port = port
|
||||
}
|
||||
|
||||
func to_sockaddr_in() -> UnsafePointer<sockaddr> {
|
||||
var data = sockaddr_in(sin_len: UInt8(sizeof(sockaddr_in)),
|
||||
sin_family: UInt8(AF_INET),
|
||||
sin_port: UInt16(port).bigEndian,
|
||||
sin_addr: in_addr(s_addr: 0),
|
||||
sin_zero: (0,0,0,0,0,0,0,0))
|
||||
inet_pton(AF_INET, addr, &(data.sin_addr));
|
||||
return UnsafePointer<sockaddr>([data]);
|
||||
}
|
||||
|
||||
func len() -> UInt8 {
|
||||
return UInt8(sizeof(sockaddr_in))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convenience wrapper class for ZeroTier/SDK/Proxy controls
|
||||
// Implemented in terms of SDK_XcodeWrapper.cpp
|
||||
class ZTSDK : NSObject
|
||||
{
|
||||
var service_thread : NSThread!
|
||||
private func ztnc_start_service(path: String?) {
|
||||
if(path == nil) {
|
||||
zt_start_service(
|
||||
NSSearchPathForDirectoriesInDomains(
|
||||
NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)[0])
|
||||
return;
|
||||
}
|
||||
zt_start_service(path!)
|
||||
}
|
||||
|
||||
// Starts the ZeroTier background service
|
||||
func start_service(path: String?) {
|
||||
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||
dispatch_async(queue) {
|
||||
self.ztnc_start_service(path)
|
||||
}
|
||||
sleep(3)
|
||||
while(service_is_running() == false) { /* waiting for service to start */ }
|
||||
}
|
||||
|
||||
// Stops the ZeroTier background service
|
||||
func stop_service() {
|
||||
zt_stop_service()
|
||||
}
|
||||
|
||||
// Returns whether the ZeroTier background service is running
|
||||
func service_is_running() -> Bool {
|
||||
return zt_service_is_running()
|
||||
}
|
||||
|
||||
// Joins a ZeroTier network
|
||||
func join_network(nwid: String) {
|
||||
zt_join_network(nwid)
|
||||
}
|
||||
|
||||
// Leaves a ZeroTier network
|
||||
func leave_network(nwid: String) {
|
||||
zt_leave_network(nwid)
|
||||
}
|
||||
|
||||
// Returns the IPV4 address of this device on a given ZeroTier network
|
||||
func get_ipv4_address(nwid: String, inout _ addrbuf: [Int8]) {
|
||||
zt_get_ipv4_address(nwid,&addrbuf)
|
||||
}
|
||||
|
||||
// Returns the IPV6 address of this device on a given ZeroTier network
|
||||
func get_ipv6_address(nwid: String, inout _ addrbuf: [Int8]) {
|
||||
zt_get_ipv6_address(nwid,&addrbuf)
|
||||
}
|
||||
|
||||
|
||||
// PROXY SERVER CONTROLS
|
||||
//
|
||||
/*
|
||||
func start_proxy_server(homepath: String, nwid: String, struct sockaddr_storage *addr) {
|
||||
zt_start_proxy_server(homepath, nwid, addr);
|
||||
}
|
||||
//
|
||||
func stop_proxy_server(nwid: String) {
|
||||
zt_stop_proxy_server(nwid);
|
||||
}
|
||||
//
|
||||
func proxy_is_running(const char *homepath, const char *nwid, struct sockaddr_storage *addr) {
|
||||
zt_start_proxy_server(homepath, nwid, addr);
|
||||
}
|
||||
//
|
||||
func get_proxy_server_address(const char *nwid, struct sockaddr_storage *addr) {
|
||||
zt_get_proxy_server_address(nwid, addr);
|
||||
}
|
||||
// Explicit ZT API wrappers
|
||||
#if !defined(__IOS__)
|
||||
// This isn't available for iOS since function interposition isn't as reliable
|
||||
func init_rpc(const char *path, const char *nwid) {
|
||||
zt_init_rpc(path, nwid);
|
||||
}
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
||||
// TODO: Verify this hasn't been broken. Should check for interface addresses based on
|
||||
// protocol version. (important)
|
||||
|
||||
// SOCKET API
|
||||
func socket(socket_family: Int32, _ socket_type: Int32, _ socket_protocol: Int32) -> Int32 {
|
||||
return zt_socket(socket_family, socket_type, socket_protocol);
|
||||
}
|
||||
|
||||
func connect(fd: Int32, _ addr: ZTAddress, _ nwid: String? = nil) -> Int32 {
|
||||
if(nwid == nil) { // no nwid is provided to check for address, try once and fail
|
||||
return zt_connect(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len()));
|
||||
}
|
||||
while(true) { // politely wait until an address is provided. simulates a blocking call
|
||||
var addrbuf = [Int8](count: 16, repeatedValue: 0)
|
||||
self.get_ipv4_address(nwid!, &addrbuf)
|
||||
let addr_str:String = String.fromCString(addrbuf)!
|
||||
if(addr_str != "-1.-1.-1.-1/-1") {
|
||||
return zt_connect(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len()));
|
||||
}
|
||||
}
|
||||
}
|
||||
func bind(fd: Int32, _ addr: ZTAddress, _ nwid: String? = nil) -> Int32 {
|
||||
if(nwid == nil) { // no nwid is provided to check for address, try once and fail
|
||||
return zt_bind(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len()));
|
||||
}
|
||||
while(true) { // politely wait until an address is provided. simulates a blocking call
|
||||
var addrbuf = [Int8](count: 16, repeatedValue: 0)
|
||||
self.get_ipv4_address(nwid!, &addrbuf)
|
||||
let addr_str:String = String.fromCString(addrbuf)!
|
||||
if(addr_str != "-1.-1.-1.-1/-1") {
|
||||
return zt_bind(Int32(fd), addr.to_sockaddr_in(), UInt32(addr.len()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func accept(fd: Int32, _ addr: ZTAddress) -> Int32 {
|
||||
return zt_accept(Int32(fd), UnsafeMutablePointer<sockaddr>([addr.data]), UnsafeMutablePointer<UInt32>([addr.len]));
|
||||
}
|
||||
|
||||
func listen(fd: Int32, _ backlog: Int16) -> Int32 {
|
||||
return zt_listen(Int32(fd), Int32(backlog));
|
||||
}
|
||||
func setsockopt(fd: Int32, _ level: Int32, _ optname: Int32, _ optval: UnsafePointer<Void>, _ optlen: Int32) -> Int32 {
|
||||
return zt_setsockopt(fd, level, optname, optval, UInt32(optlen));
|
||||
}
|
||||
|
||||
func getsockopt(fd: Int32, _ level: Int32, _ optname: Int32, _ optval: UnsafeMutablePointer<Void>, _ optlen: UInt32) -> Int32 {
|
||||
return zt_getsockopt(fd, level, optname, optval, UnsafeMutablePointer<UInt32>([optlen]));
|
||||
}
|
||||
|
||||
func close(fd: Int32) -> Int32 {
|
||||
return zt_close(fd);
|
||||
}
|
||||
|
||||
func getsockname(fd: Int32, _ addr: ZTAddress) -> Int32 {
|
||||
return zt_getsockname(fd, UnsafeMutablePointer<sockaddr>([addr.data]), UnsafeMutablePointer<UInt32>([addr.len]));
|
||||
}
|
||||
|
||||
func getpeername(fd: Int32, _ addr: ZTAddress) -> Int32 {
|
||||
return zt_getpeername(fd, UnsafeMutablePointer<sockaddr>([addr.data]), UnsafeMutablePointer<UInt32>([addr.len]));
|
||||
}
|
||||
|
||||
func fcntl(fd: Int32, _ cmd: Int32, _ flags: Int32) -> Int32 {
|
||||
return zt_fcntl(fd, cmd, flags);
|
||||
}
|
||||
|
||||
func recvfrom(fd: Int32, _ buf: UnsafeMutablePointer<Void>, _ len: Int32, _ flags: Int32, _ addr: ZTAddress) -> Int32 {
|
||||
return zt_recvfrom(fd, buf, Int(len), flags, UnsafeMutablePointer<sockaddr>([addr.data]), UnsafeMutablePointer<UInt32>([addr.len]));
|
||||
}
|
||||
|
||||
func sendto(fd: Int32, _ buf: UnsafePointer<Void>, _ len: Int32, _ flags: Int32, _ addr: ZTAddress) -> Int32 {
|
||||
return zt_sendto(fd, buf, Int(len), flags, addr.to_sockaddr_in(), UInt32(addr.len()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user