2017-04-06 19:16:01 -07:00
|
|
|
/*
|
2017-05-04 15:53:38 -07:00
|
|
|
* ZeroTier SDK - Network Virtualization Everywhere
|
2017-05-04 15:35:50 -07:00
|
|
|
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
2017-04-06 19:16:01 -07:00
|
|
|
*
|
|
|
|
|
* 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/>.
|
2017-05-04 15:35:50 -07:00
|
|
|
*
|
|
|
|
|
* --
|
|
|
|
|
*
|
|
|
|
|
* You can be released from the requirements of the license by purchasing
|
|
|
|
|
* a commercial license. Buying such a license is mandatory as soon as you
|
|
|
|
|
* develop commercial closed-source software that incorporates or links
|
|
|
|
|
* directly against ZeroTier software without disclosing the source code
|
|
|
|
|
* of your own application.
|
2017-04-06 19:16:01 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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>
|
|
|
|
|
|
2017-04-21 14:56:42 -07:00
|
|
|
// ZT
|
2017-04-06 19:16:01 -07:00
|
|
|
#include "OneService.hpp"
|
|
|
|
|
#include "Utils.hpp"
|
|
|
|
|
#include "OSUtils.hpp"
|
|
|
|
|
#include "InetAddress.hpp"
|
|
|
|
|
#include "ZeroTierOne.h"
|
|
|
|
|
|
2017-04-21 14:56:42 -07:00
|
|
|
// SDK
|
2017-04-06 19:16:01 -07:00
|
|
|
#include "SocketTap.hpp"
|
|
|
|
|
#include "ZeroTierSDK.h"
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static ZeroTier::OneService *zt1Service;
|
|
|
|
|
|
2017-04-14 17:23:28 -07:00
|
|
|
namespace ZeroTier {
|
|
|
|
|
std::string homeDir; // The resultant platform-specific dir we *must* use internally
|
|
|
|
|
std::string netDir; // Where network .conf files are to be written
|
2017-04-06 19:16:01 -07:00
|
|
|
|
2017-04-20 13:39:46 -07:00
|
|
|
/*
|
|
|
|
|
* Global reference to stack
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
picoTCP *picostack = NULL;
|
2017-04-20 13:39:46 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* "sockets" that have been created but not bound to a SocketTap interface yet
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
std::map<int, Connection*> UnassignedConnections;
|
2017-04-20 13:39:46 -07:00
|
|
|
|
|
|
|
|
// FIXME: make sure these are properly deleted
|
|
|
|
|
/*
|
|
|
|
|
* For fast lookup of Connections and SocketTaps via given file descriptor
|
|
|
|
|
*/
|
2017-05-01 18:18:20 -07:00
|
|
|
std::map<int, std::pair<Connection*,SocketTap*>*> fdmap;
|
2017-04-20 13:39:46 -07:00
|
|
|
|
|
|
|
|
ZeroTier::Mutex _multiplexer_lock;
|
|
|
|
|
ZeroTier::Mutex _accepted_connection_lock;
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2017-04-07 17:56:05 -07:00
|
|
|
/* SDK Socket API - Language Bindings are written in terms of these */
|
2017-04-06 19:16:01 -07:00
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void zts_start(const char *path)
|
|
|
|
|
{
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service)
|
|
|
|
|
return;
|
|
|
|
|
if(ZeroTier::picostack)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ZeroTier::picostack = new ZeroTier::picoTCP();
|
|
|
|
|
pico_stack_init();
|
|
|
|
|
|
2017-04-06 19:16:01 -07:00
|
|
|
DEBUG_INFO("path=%s", path);
|
|
|
|
|
if(path)
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::homeDir = path;
|
2017-04-07 17:56:05 -07:00
|
|
|
pthread_t service_thread;
|
|
|
|
|
pthread_create(&service_thread, NULL, _start_service, (void *)(path));
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zts_stop() {
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service) {
|
|
|
|
|
zt1Service->terminate();
|
|
|
|
|
zt1Service->removeNets();
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
void zts_join(const char * nwid) {
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service) {
|
|
|
|
|
std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf";
|
2017-04-14 17:23:28 -07:00
|
|
|
if(!ZeroTier::OSUtils::mkdir(ZeroTier::netDir))
|
|
|
|
|
DEBUG_ERROR("unable to create: %s", ZeroTier::netDir.c_str());
|
2017-04-07 17:56:05 -07:00
|
|
|
if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), ""))
|
|
|
|
|
DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str());
|
|
|
|
|
zt1Service->join(nwid);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
void zts_join_soft(const char * filepath, const char * nwid) {
|
2017-04-06 19:16:01 -07:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
void zts_leave(const char * nwid) {
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service)
|
|
|
|
|
zt1Service->leave(nwid);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
void zts_leave_soft(const char * filepath, const char * nwid) {
|
2017-04-06 19:16:01 -07:00
|
|
|
std::string net_dir = std::string(filepath) + "/networks.d/";
|
|
|
|
|
ZeroTier::OSUtils::rm((net_dir + nwid + ".conf").c_str());
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_get_homepath(char *homePath, int len) {
|
2017-04-14 17:23:28 -07:00
|
|
|
if(ZeroTier::homeDir.length()) {
|
|
|
|
|
memset(homePath, 0, len);
|
|
|
|
|
memcpy(homePath, ZeroTier::homeDir.c_str(), len < ZeroTier::homeDir.length() ? len : ZeroTier::homeDir.length());
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_core_version(char *ver) {
|
|
|
|
|
int major, minor, revision;
|
|
|
|
|
ZT_version(&major, &minor, &revision);
|
|
|
|
|
sprintf(ver, "%d.%d.%d", major, minor, revision);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zts_sdk_version(char *ver) {
|
|
|
|
|
sprintf(ver, "%d.%d.%d", ZT_SDK_VERSION_MAJOR, ZT_SDK_VERSION_MINOR, ZT_SDK_VERSION_REVISION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zts_get_device_id(char *devID) {
|
|
|
|
|
if(zt1Service) {
|
|
|
|
|
char id[ZT_ID_LEN+1];
|
|
|
|
|
sprintf(id, "%lx",zt1Service->getNode()->address());
|
|
|
|
|
memcpy(devID, id, ZT_ID_LEN+1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else // Service isn't online, try to read ID from file
|
|
|
|
|
{
|
|
|
|
|
std::string fname("identity.public");
|
2017-04-14 17:23:28 -07:00
|
|
|
std::string fpath(ZeroTier::homeDir);
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
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(), ZT_ID_LEN); // first 10 bytes of file
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
int zts_running() {
|
2017-04-07 17:56:05 -07:00
|
|
|
return !zt1Service ? false : zt1Service->isRunning();
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-04-07 17:56:05 -07:00
|
|
|
int zts_has_ipv4_address(const char *nwid)
|
|
|
|
|
{
|
|
|
|
|
char ipv4_addr[ZT_MAX_IPADDR_LEN];
|
|
|
|
|
memset(ipv4_addr, 0, ZT_MAX_IPADDR_LEN);
|
|
|
|
|
zts_get_ipv4_address(nwid, ipv4_addr, ZT_MAX_IPADDR_LEN);
|
|
|
|
|
return strcmp(ipv4_addr, "\0");
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
|
2017-04-07 17:56:05 -07:00
|
|
|
int zts_has_ipv6_address(const char *nwid)
|
|
|
|
|
{
|
|
|
|
|
char ipv6_addr[ZT_MAX_IPADDR_LEN];
|
|
|
|
|
memset(ipv6_addr, 0, ZT_MAX_IPADDR_LEN);
|
|
|
|
|
zts_get_ipv6_address(nwid, ipv6_addr, ZT_MAX_IPADDR_LEN);
|
|
|
|
|
return strcmp(ipv6_addr, "\0");
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
|
|
|
|
|
int zts_has_address(const char *nwid)
|
|
|
|
|
{
|
2017-04-07 17:56:05 -07:00
|
|
|
return zts_has_ipv4_address(nwid) || zts_has_ipv6_address(nwid);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_get_ipv4_address(const char *nwid, char *addrstr, const int addrlen)
|
2017-04-06 19:16:01 -07:00
|
|
|
{
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service) {
|
|
|
|
|
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
|
|
|
|
ZeroTier::SocketTap *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();
|
|
|
|
|
int len = addrlen < addr.length() ? addrlen : addr.length();
|
|
|
|
|
memset(addrstr, 0, len);
|
|
|
|
|
memcpy(addrstr, addr.c_str(), len);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
else
|
|
|
|
|
memcpy(addrstr, "\0", 1);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_get_ipv6_address(const char *nwid, char *addrstr, const int addrlen)
|
2017-04-06 19:16:01 -07:00
|
|
|
{
|
2017-04-07 17:56:05 -07:00
|
|
|
if(zt1Service) {
|
|
|
|
|
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
|
|
|
|
ZeroTier::SocketTap *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();
|
|
|
|
|
int len = addrlen < addr.length() ? addrlen : addr.length();
|
|
|
|
|
memset(addrstr, 0, len);
|
|
|
|
|
memcpy(addrstr, addr.c_str(), len);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2017-04-07 17:56:05 -07:00
|
|
|
memcpy(addrstr, "\0", 1);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long zts_get_peer_count() {
|
|
|
|
|
if(zt1Service)
|
|
|
|
|
return zt1Service->getNode()->peers()->peerCount;
|
|
|
|
|
else
|
2017-04-06 19:16:01 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
2017-04-06 19:16:01 -07:00
|
|
|
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;
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_enable_http_control_plane()
|
|
|
|
|
{
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
void zts_disable_http_control_plane()
|
|
|
|
|
{
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2017-04-14 17:23:28 -07:00
|
|
|
/* SocketTap Multiplexer Functionality */
|
2017-04-07 17:56:05 -07:00
|
|
|
/* - This section of the API is used to implement the general socket */
|
|
|
|
|
/* controls. Basically this is designed to handle socket provisioning */
|
|
|
|
|
/* requests when no SocketTap is yet initialized, and as a way to */
|
|
|
|
|
/* determine which SocketTap is to be used for a particular connect() or */
|
2017-04-14 17:23:28 -07:00
|
|
|
/* bind() call. This enables multi-network support */
|
2017-04-07 17:56:05 -07:00
|
|
|
/****************************************************************************/
|
|
|
|
|
|
2017-04-21 14:56:42 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
socket fd = 0 (nwid=X)---\ /--- SocketTap=A // e.x. 172.27.0.0/?
|
|
|
|
|
\ /
|
|
|
|
|
socket fd = 1 (nwid=Y)--------Multiplexed z* calls-------- SocketTap=B // e.x. 192.168.0.1/16
|
|
|
|
|
/ \
|
|
|
|
|
socket fd = 2 (nwid=Z)---/ \--- SocketTap=C // e.x. 10.9.9.0/24
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[ ] [EACCES] Permission to create a socket of the specified type and/or protocol is denied.
|
|
|
|
|
[ ] [EAFNOSUPPORT] The specified address family is not supported.
|
|
|
|
|
[ ] [EMFILE] The per-process descriptor table is full.
|
|
|
|
|
[ ] [ENFILE] The system file table is full.
|
|
|
|
|
[ ] [ENOBUFS] Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed.
|
|
|
|
|
[ ] [ENOMEM] Insufficient memory was available to fulfill the request.
|
|
|
|
|
[ ] [EPROTONOSUPPORT] The protocol type or the specified protocol is not supported within this domain.
|
|
|
|
|
[ ] [EPROTOTYPE] The socket type is not supported by the protocol.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// int socket_family, int socket_type, int protocol
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_socket(ZT_SOCKET_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("UnassConn=%d, fdmap=%d", ZeroTier::UnassignedConnections.size(), ZeroTier::fdmap.size());
|
2017-04-07 17:56:05 -07:00
|
|
|
DEBUG_INFO();
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
2017-04-07 17:56:05 -07:00
|
|
|
ZeroTier::Connection *conn = new ZeroTier::Connection();
|
2017-05-04 13:06:39 -07:00
|
|
|
int err = 0, protocol_version = 0;
|
2017-04-07 17:56:05 -07:00
|
|
|
// set up pico_socket
|
|
|
|
|
struct pico_socket * psock;
|
2017-05-01 18:18:20 -07:00
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
// TODO: check ifdef logic here
|
2017-04-07 17:56:05 -07:00
|
|
|
#if defined(SDK_IPV4)
|
|
|
|
|
protocol_version = PICO_PROTO_IPV4;
|
2017-05-01 18:18:20 -07:00
|
|
|
#endif
|
|
|
|
|
#if defined(SDK_IPV6)
|
2017-04-07 17:56:05 -07:00
|
|
|
protocol_version = PICO_PROTO_IPV6;
|
|
|
|
|
#endif
|
2017-05-01 18:18:20 -07:00
|
|
|
|
2017-04-07 17:56:05 -07:00
|
|
|
if(socket_type == SOCK_DGRAM) {
|
2017-04-14 17:23:28 -07:00
|
|
|
psock = pico_socket_open(
|
|
|
|
|
protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity);
|
2017-04-07 17:56:05 -07:00
|
|
|
}
|
|
|
|
|
if(socket_type == SOCK_STREAM) {
|
2017-04-14 17:23:28 -07:00
|
|
|
psock = pico_socket_open(
|
|
|
|
|
protocol_version, PICO_PROTO_TCP, &ZeroTier::picoTCP::pico_cb_socket_activity);
|
|
|
|
|
}
|
|
|
|
|
// set up Unix Domain socketpair (used for data later on)
|
|
|
|
|
if(psock) {
|
|
|
|
|
conn->socket_family = socket_family;
|
|
|
|
|
conn->socket_type = socket_type;
|
|
|
|
|
conn->picosock = psock;
|
|
|
|
|
memset(conn->rxbuf, 0, ZT_UDP_RX_BUF_SZ);
|
|
|
|
|
ZeroTier::UnassignedConnections[conn->app_fd] = conn;
|
|
|
|
|
err = conn->app_fd; // return one end of the socketpair
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
DEBUG_ERROR("failed to create pico_socket");
|
|
|
|
|
err = -1;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[ ] [EACCES] The destination address is a broadcast address and the socket option SO_BROADCAST is not set.
|
|
|
|
|
[ ] [EADDRINUSE] The address is already in use.
|
|
|
|
|
[ ] [EADDRNOTAVAIL] The specified address is not available on this machine.
|
|
|
|
|
[ ] [EAFNOSUPPORT] Addresses in the specified address family cannot be used with this socket.
|
|
|
|
|
[ ] [EALREADY] The socket is non-blocking and a previous connection attempt has not yet been completed.
|
|
|
|
|
[ ] [EBADF] socket is not a valid descriptor.
|
|
|
|
|
[ ] [ECONNREFUSED] The attempt to connect was ignored (because the target is not listening for connections) or explicitly rejected.
|
|
|
|
|
[ ] [EFAULT] The address parameter specifies an area outside the process address space.
|
|
|
|
|
[ ] [EHOSTUNREACH] The target host cannot be reached (e.g., down, disconnected).
|
|
|
|
|
[ ] [EINPROGRESS] The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) for completion by selecting the socket for writing.
|
|
|
|
|
[ ] [EINTR] Its execution was interrupted by a signal.
|
|
|
|
|
[ ] [EINVAL] An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
|
|
|
|
|
[ ] [EISCONN] The socket is already connected.
|
|
|
|
|
[ ] [ENETDOWN] The local network interface is not functioning.
|
|
|
|
|
[ ] [ENETUNREACH] The network isn't reachable from this host.
|
|
|
|
|
[ ] [ENOBUFS] The system call was unable to allocate a needed memory buffer.
|
|
|
|
|
[ ] [ENOTSOCK] socket is not a file descriptor for a socket.
|
|
|
|
|
[ ] [EOPNOTSUPP] Because socket is listening, no connection is allowed.
|
|
|
|
|
[ ] [EPROTOTYPE] address has a different type than the socket that is bound to the specified peer address.
|
|
|
|
|
[ ] [ETIMEDOUT] Connection establishment timed out without establishing a connection.
|
|
|
|
|
[ ] [ECONNRESET] Remote host reset the connection request.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_connect(ZT_CONNECT_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-14 17:23:28 -07:00
|
|
|
if(!zt1Service) {
|
2017-04-20 13:39:46 -07:00
|
|
|
DEBUG_ERROR("Service not started. Call zts_start(path) first");
|
2017-04-14 17:23:28 -07:00
|
|
|
// errno = ?
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
|
|
|
|
int err;
|
|
|
|
|
ZeroTier::Connection *conn = ZeroTier::UnassignedConnections[fd];
|
|
|
|
|
ZeroTier::SocketTap *tap;
|
|
|
|
|
|
|
|
|
|
if(conn) {
|
|
|
|
|
char ipstr[INET6_ADDRSTRLEN];//, nm_str[INET6_ADDRSTRLEN];
|
|
|
|
|
memset(ipstr, 0, INET6_ADDRSTRLEN);
|
|
|
|
|
ZeroTier::InetAddress iaddr;
|
|
|
|
|
|
|
|
|
|
if(conn->socket_family == AF_INET) {
|
|
|
|
|
// FIXME: Fix this typecast mess
|
|
|
|
|
inet_ntop(AF_INET,
|
|
|
|
|
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
|
|
|
|
|
}
|
|
|
|
|
if(conn->socket_family == AF_INET6) {
|
|
|
|
|
// FIXME: Fix this typecast mess
|
|
|
|
|
inet_ntop(AF_INET6,
|
|
|
|
|
(const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
|
|
|
|
|
}
|
2017-05-03 21:12:26 -07:00
|
|
|
iaddr.fromString(ipstr+std::string("/88"));
|
2017-05-01 18:18:20 -07:00
|
|
|
//DEBUG_INFO("ipstr= %s", ipstr);
|
|
|
|
|
//DEBUG_INFO("iaddr= %s", iaddr.toString().c_str());
|
2017-04-14 17:23:28 -07:00
|
|
|
tap = zt1Service->getTap(iaddr);
|
|
|
|
|
if(!tap) {
|
|
|
|
|
// TODO: More canonical error?
|
|
|
|
|
DEBUG_ERROR("no route to host");
|
2017-04-07 17:56:05 -07:00
|
|
|
// errno = ?
|
|
|
|
|
err = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-04-20 13:39:46 -07:00
|
|
|
// pointer to tap we use in callbacks from the stack
|
|
|
|
|
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
|
2017-04-21 14:56:42 -07:00
|
|
|
// DEBUG_INFO("found appropriate SocketTap");
|
2017-04-20 13:39:46 -07:00
|
|
|
// Semantically: tap->stack->connect
|
|
|
|
|
err = tap->Connect(conn, fd, addr, addrlen);
|
|
|
|
|
if(err == 0) {
|
|
|
|
|
tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
|
|
|
|
|
conn->tap = tap;
|
|
|
|
|
}
|
|
|
|
|
// Wrap the socketpair we created earlier
|
|
|
|
|
// For I/O loop participation and referencing the PhySocket's parent Connection in callbacks
|
2017-04-21 14:56:42 -07:00
|
|
|
conn->sock = tap->_phy.wrapSocket(conn->sdk_fd, conn);
|
2017-05-01 18:18:20 -07:00
|
|
|
//DEBUG_INFO("wrapping conn->sdk_fd = %d", conn->sdk_fd);
|
|
|
|
|
//DEBUG_INFO(" conn->app_fd = %d", conn->app_fd);
|
2017-04-07 17:56:05 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-04-14 17:23:28 -07:00
|
|
|
DEBUG_ERROR("unable to locate connection");
|
|
|
|
|
// errno = ?
|
2017-04-07 17:56:05 -07:00
|
|
|
err = -1;
|
|
|
|
|
}
|
2017-04-20 13:39:46 -07:00
|
|
|
ZeroTier::UnassignedConnections.erase(fd);
|
2017-05-01 18:18:20 -07:00
|
|
|
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
2017-04-20 13:39:46 -07:00
|
|
|
|
|
|
|
|
// NOTE: pico_socket_connect() will return 0 if no error happens immediately, but that doesn't indicate
|
|
|
|
|
// the connection was completed, for that we must wait for a callback from the stack. During that
|
|
|
|
|
// callback we will place the Connection in a ZT_SOCK_STATE_UNHANDLED_CONNECTED state to signal
|
|
|
|
|
// to the multiplexer logic that this connection is complete and a success value can be sent to the
|
|
|
|
|
// user application
|
|
|
|
|
|
|
|
|
|
// non-blocking
|
2017-05-01 18:18:20 -07:00
|
|
|
if(err == 0 && false) {
|
2017-04-20 13:39:46 -07:00
|
|
|
errno = EINPROGRESS;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// blocking
|
2017-05-01 18:18:20 -07:00
|
|
|
// FIXME: Double check that accept/connect queues in multithreaded apps don't get mixed up
|
2017-04-20 13:39:46 -07:00
|
|
|
if(err == 0 && true) {
|
2017-05-01 18:18:20 -07:00
|
|
|
bool complete = false;
|
2017-04-20 13:39:46 -07:00
|
|
|
while(true)
|
|
|
|
|
{
|
2017-04-21 14:56:42 -07:00
|
|
|
// FIXME: locking and unlocking so often might cause a performance bottleneck while outgoing connections
|
|
|
|
|
// are being established (also applies to accept())
|
2017-04-20 13:39:46 -07:00
|
|
|
usleep(ZT_CONNECT_RECHECK_DELAY * 1000);
|
|
|
|
|
tap->_tcpconns_m.lock();
|
|
|
|
|
for(int i=0; i<tap->_Connections.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if(tap->_Connections[i]->state == PICO_ERR_ECONNRESET) {
|
|
|
|
|
errno = ECONNRESET;
|
2017-05-01 18:18:20 -07:00
|
|
|
err = -1;
|
2017-04-20 13:39:46 -07:00
|
|
|
}
|
|
|
|
|
if(tap->_Connections[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) {
|
|
|
|
|
tap->_Connections[i]->state = ZT_SOCK_STATE_CONNECTED;
|
|
|
|
|
errno = 0;
|
2017-05-01 18:18:20 -07:00
|
|
|
err = 0; // complete
|
|
|
|
|
complete = true;
|
2017-04-20 13:39:46 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tap->_tcpconns_m.unlock();
|
2017-05-01 18:18:20 -07:00
|
|
|
if(complete)
|
|
|
|
|
break;
|
2017-04-20 13:39:46 -07:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
return err;
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[ ] [EBADF] S is not a valid descriptor.
|
|
|
|
|
[ ] [ENOTSOCK] S is not a socket.
|
|
|
|
|
[ ] [EADDRNOTAVAIL] The specified address is not available from the local
|
|
|
|
|
machine.
|
|
|
|
|
[ ] [EADDRINUSE] The specified address is already in use.
|
|
|
|
|
[ ] [EINVAL] The socket is already bound to an address.
|
|
|
|
|
[ ] [EACCES] The requested address is protected, and the current
|
|
|
|
|
user has inadequate permission to access it.
|
|
|
|
|
[ ] [EFAULT] The name parameter is not in a valid part of the user
|
|
|
|
|
address space.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_bind(ZT_BIND_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-07 17:56:05 -07:00
|
|
|
if(!zt1Service) {
|
2017-04-20 13:39:46 -07:00
|
|
|
DEBUG_ERROR("Service not started. Call zts_start(path) first");
|
2017-04-07 17:56:05 -07:00
|
|
|
// errno = ?
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
2017-04-07 17:56:05 -07:00
|
|
|
int err;
|
|
|
|
|
ZeroTier::Connection *conn = ZeroTier::UnassignedConnections[fd];
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::SocketTap *tap;
|
|
|
|
|
|
|
|
|
|
if(conn) {
|
2017-05-01 18:18:20 -07:00
|
|
|
char ipstr[INET6_ADDRSTRLEN]; //, nm_str[INET6_ADDRSTRLEN];
|
2017-04-07 17:56:05 -07:00
|
|
|
memset(ipstr, 0, INET6_ADDRSTRLEN);
|
|
|
|
|
ZeroTier::InetAddress iaddr;
|
|
|
|
|
|
|
|
|
|
if(conn->socket_family == AF_INET) {
|
2017-04-14 17:23:28 -07:00
|
|
|
inet_ntop(AF_INET,
|
|
|
|
|
(const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN);
|
2017-04-07 17:56:05 -07:00
|
|
|
}
|
|
|
|
|
if(conn->socket_family == AF_INET6) {
|
2017-04-14 17:23:28 -07:00
|
|
|
inet_ntop(AF_INET6,
|
|
|
|
|
(const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN);
|
2017-04-07 17:56:05 -07:00
|
|
|
}
|
|
|
|
|
iaddr.fromString(ipstr);
|
2017-04-14 17:23:28 -07:00
|
|
|
tap = zt1Service->getTap(iaddr);
|
2017-04-07 17:56:05 -07:00
|
|
|
|
|
|
|
|
if(!tap) {
|
2017-04-14 17:23:28 -07:00
|
|
|
// TODO: More canonical error?
|
|
|
|
|
DEBUG_ERROR("no appropriate interface to bind to");
|
2017-04-07 17:56:05 -07:00
|
|
|
// errno = ?
|
|
|
|
|
err = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-04-21 14:56:42 -07:00
|
|
|
//DEBUG_INFO("found appropriate SocketTap");
|
|
|
|
|
//DEBUG_INFO("conn->picosock = %p", conn->picosock);
|
2017-04-20 13:39:46 -07:00
|
|
|
conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn);
|
2017-04-14 17:23:28 -07:00
|
|
|
tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on
|
|
|
|
|
err = tap->Bind(conn, fd, addr, addrlen); // Semantically: tap->stack->connect
|
|
|
|
|
conn->tap = tap;
|
2017-04-07 17:56:05 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
DEBUG_ERROR("unable to locate connection");
|
|
|
|
|
// errno = ?
|
|
|
|
|
err = -1;
|
|
|
|
|
}
|
2017-05-01 18:18:20 -07:00
|
|
|
ZeroTier::fdmap[fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(conn, tap);
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
2017-04-07 17:56:05 -07:00
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[ ] [EACCES] The current process has insufficient privileges.
|
|
|
|
|
[ ] [EBADF] The argument socket is not a valid file descriptor.
|
|
|
|
|
[ ] [EDESTADDRREQ] The socket is not bound to a local address and the protocol does not support listening on an unbound socket.
|
|
|
|
|
[ ] [EINVAL] socket is already connected.
|
|
|
|
|
[ ] [ENOTSOCK] The argument socket does not reference a socket.
|
|
|
|
|
[ ] [EOPNOTSUPP] The socket is not of a type that supports the operation listen().
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_listen(ZT_LISTEN_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-14 17:23:28 -07:00
|
|
|
if(!zt1Service) {
|
2017-04-20 13:39:46 -07:00
|
|
|
DEBUG_ERROR("Service not started. Call zts_start(path) first");
|
2017-04-14 17:23:28 -07:00
|
|
|
// errno = ?
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
int err;
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
2017-05-01 18:18:20 -07:00
|
|
|
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
|
2017-04-20 13:39:46 -07:00
|
|
|
if(!p) {
|
|
|
|
|
DEBUG_ERROR("unable to locate connection pair (did you zbind()?");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::Connection *conn = p->first;
|
|
|
|
|
ZeroTier::SocketTap *tap = p->second;
|
2017-04-14 17:23:28 -07:00
|
|
|
|
|
|
|
|
if(!tap || !conn) {
|
|
|
|
|
DEBUG_ERROR("unable to locate tap interface for file descriptor");
|
2017-04-20 13:39:46 -07:00
|
|
|
return -1;
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
2017-04-21 14:56:42 -07:00
|
|
|
err = tap->Listen(conn, fd, backlog);
|
2017-05-01 18:18:20 -07:00
|
|
|
//DEBUG_INFO("put conn=%p into LISTENING state (err=%d)", conn, err);
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[ ] [EBADF] The descriptor is invalid.
|
|
|
|
|
[ ] [ENOTSOCK] The descriptor references a file, not a socket.
|
|
|
|
|
[ ] [EOPNOTSUPP] The referenced socket is not of type SOCK_STREAM.
|
|
|
|
|
[ ] [EFAULT] The addr parameter is not in a writable part of the
|
|
|
|
|
user address space.
|
|
|
|
|
[ ] [EWOULDBLOCK] The socket is marked non-blocking and no connections
|
|
|
|
|
are present to be accepted.
|
|
|
|
|
[ ] [EMFILE] The per-process descriptor table is full.
|
|
|
|
|
[ ] [ENFILE] The system file table is full.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_accept(ZT_ACCEPT_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
|
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
|
|
|
|
int err = -1;
|
|
|
|
|
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
|
2017-04-21 14:56:42 -07:00
|
|
|
if(!p) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_ERROR("unable to locate connection pair (did you zbind())?");
|
2017-04-21 14:56:42 -07:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::Connection *conn = p->first;
|
|
|
|
|
ZeroTier::SocketTap *tap = p->second;
|
2017-05-01 18:18:20 -07:00
|
|
|
ZeroTier::Connection *accepted_conn;
|
|
|
|
|
|
2017-04-14 17:23:28 -07:00
|
|
|
// BLOCKING: loop and keep checking until we find a newly accepted connection
|
|
|
|
|
if(true) {
|
|
|
|
|
while(true) {
|
|
|
|
|
usleep(ZT_ACCEPT_RECHECK_DELAY * 1000);
|
2017-05-01 18:18:20 -07:00
|
|
|
accepted_conn = tap->Accept(conn);
|
|
|
|
|
if(accepted_conn)
|
|
|
|
|
break; // accepted fd = err
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// NON-BLOCKING: only check for a new connection once
|
|
|
|
|
else
|
2017-05-01 18:18:20 -07:00
|
|
|
accepted_conn = tap->Accept(conn);
|
|
|
|
|
|
|
|
|
|
if(accepted_conn) {
|
|
|
|
|
ZeroTier::fdmap[accepted_conn->app_fd] = new std::pair<ZeroTier::Connection*,ZeroTier::SocketTap*>(accepted_conn, tap);
|
|
|
|
|
err = accepted_conn->app_fd;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
2017-04-07 17:56:05 -07:00
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.
|
|
|
|
|
Errors
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
EBADF The descriptor is invalid.
|
|
|
|
|
ECONNABORTED A connection has been aborted.
|
|
|
|
|
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).
|
|
|
|
|
EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
|
|
|
|
|
EINVAL (accept4()) invalid value in flags.
|
|
|
|
|
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.
|
|
|
|
|
ENOTSOCK The descriptor references a file, not a socket.
|
|
|
|
|
EOPNOTSUPP The referenced socket is not of type SOCK_STREAM.
|
|
|
|
|
EPROTO Protocol error.
|
|
|
|
|
|
|
|
|
|
In addition, Linux accept() may fail if:
|
|
|
|
|
|
|
|
|
|
EPERM Firewall rules forbid connection.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
#if defined(__linux__)
|
|
|
|
|
int zts_accept4(ZT_ACCEPT4_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
[ ] [EBADF] The argument s is not a valid descriptor.
|
|
|
|
|
[ ] [ENOTSOCK] The argument s is a file, not a socket.
|
|
|
|
|
[ ] [ENOPROTOOPT] The option is unknown at the level indicated.
|
|
|
|
|
[ ] [EFAULT] The address pointed to by optval is not in a valid
|
|
|
|
|
part of the process address space. For getsockopt(),
|
|
|
|
|
this error may also be returned if optlen is not in a
|
|
|
|
|
valid part of the process address space.
|
|
|
|
|
[ ] [EDOM] The argument value is out of bounds.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_setsockopt(ZT_SETSOCKOPT_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
|
|
|
|
int err = setsockopt(fd, level, optname, optval, optlen);
|
|
|
|
|
DEBUG_INFO("err = %d", err);
|
|
|
|
|
return err;
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
[ ] [EBADF] The argument s is not a valid descriptor.
|
|
|
|
|
[ ] [ENOTSOCK] The argument s is a file, not a socket.
|
|
|
|
|
[ ] [ENOPROTOOPT] The option is unknown at the level indicated.
|
|
|
|
|
[ ] [EFAULT] The address pointed to by optval is not in a valid
|
|
|
|
|
part of the process address space. For getsockopt(),
|
|
|
|
|
this error may also be returned if optlen is not in a
|
|
|
|
|
valid part of the process address space.
|
|
|
|
|
[ ] [EDOM] The argument value is out of bounds.
|
|
|
|
|
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_getsockopt(ZT_GETSOCKOPT_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
|
|
|
|
return getsockopt(fd, level, optname, optval, optlen);
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
[ ] [EBADF] The argument s is not a valid descriptor.
|
|
|
|
|
[ ] [ENOTSOCK] The argument s is a file, not a socket.
|
|
|
|
|
[ ] [ENOBUFS] Insufficient resources were available in the system to
|
|
|
|
|
perform the operation.
|
|
|
|
|
[ ] [EFAULT] The name parameter points to memory not in a valid
|
|
|
|
|
part of the process address space.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_getsockname(ZT_GETSOCKNAME_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
[ ] [EBADF] The argument s is not a valid descriptor.
|
|
|
|
|
[ ] [ENOTSOCK] The argument s is a file, not a socket.
|
|
|
|
|
[ ] [ENOTCONN] The socket is not connected.
|
|
|
|
|
[ ] [ENOBUFS] Insufficient resources were available in the system to
|
|
|
|
|
perform the operation.
|
|
|
|
|
[ ] [EFAULT] The name parameter points to memory not in a valid
|
|
|
|
|
part of the process address space.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_getpeername(ZT_GETPEERNAME_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 18:18:20 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Linux:
|
|
|
|
|
|
|
|
|
|
See: http://yarchive.net/comp/linux/close_return_value.html
|
|
|
|
|
|
|
|
|
|
Darwin:
|
|
|
|
|
|
|
|
|
|
[OK] [EBADF] fildes is not a valid, active file descriptor.
|
|
|
|
|
[ ] [EINTR] Its execution was interrupted by a signal.
|
|
|
|
|
[ ] [EIO] A previously-uncommitted write(2) encountered an input/output error.
|
|
|
|
|
*/
|
2017-04-14 17:23:28 -07:00
|
|
|
int zts_close(ZT_CLOSE_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
|
|
|
|
// TODO: Close should handle situations where data is still being
|
|
|
|
|
// processed by the SocketTap (such as a zwrite() call)
|
|
|
|
|
// check out SO_LINGER
|
2017-04-20 13:39:46 -07:00
|
|
|
ZeroTier::_multiplexer_lock.lock();
|
2017-05-01 18:18:20 -07:00
|
|
|
|
|
|
|
|
std::pair<ZeroTier::Connection*, ZeroTier::SocketTap*> *p = ZeroTier::fdmap[fd];
|
|
|
|
|
if(!p) {
|
|
|
|
|
DEBUG_ERROR("unable to locate connection pair.?");
|
|
|
|
|
errno = EBADF;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ZeroTier::Connection *conn = p->first;
|
|
|
|
|
ZeroTier::SocketTap *tap = p->second;
|
|
|
|
|
|
|
|
|
|
if(ZT_SOCK_BEHAVIOR_LINGER) {
|
|
|
|
|
socklen_t optlen;
|
|
|
|
|
struct linger so_linger;
|
|
|
|
|
zts_getsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, &optlen);
|
|
|
|
|
if (so_linger.l_linger != 0) {
|
|
|
|
|
sleep(so_linger.l_linger); // do the linger!
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-20 13:39:46 -07:00
|
|
|
// Tell the tap to stop monitoring this PhySocket
|
|
|
|
|
tap->Close(conn);
|
2017-05-01 18:18:20 -07:00
|
|
|
// delete objects
|
|
|
|
|
// FIXME: double check this
|
|
|
|
|
delete p;
|
|
|
|
|
ZeroTier::fdmap[fd] = NULL; // erase?
|
2017-04-20 13:39:46 -07:00
|
|
|
ZeroTier::_multiplexer_lock.unlock();
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zts_fcntl(ZT_FCNTL_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
|
|
|
|
return fcntl(fd, cmd, flags);
|
2017-04-14 17:23:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t zts_sendto(ZT_SENDTO_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t zts_sendmsg(ZT_SENDMSG_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t zts_recvfrom(ZT_RECVFROM_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t zts_recvmsg(ZT_RECVMSG_SIG)
|
|
|
|
|
{
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-20 13:39:46 -07:00
|
|
|
// TODO
|
2017-04-14 17:23:28 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zts_read(ZT_READ_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-14 17:23:28 -07:00
|
|
|
return read(fd, buf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zts_write(ZT_WRITE_SIG) {
|
2017-05-01 18:18:20 -07:00
|
|
|
DEBUG_INFO("fd = %d", fd);
|
2017-04-14 17:23:28 -07:00
|
|
|
return write(fd, buf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-07 17:56:05 -07:00
|
|
|
/****************************************************************************/
|
|
|
|
|
/* SDK Socket API (Java Native Interface JNI) */
|
|
|
|
|
/* JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME */
|
|
|
|
|
/****************************************************************************/
|
2017-04-06 19:16:01 -07:00
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
|
|
|
|
|
#if defined(SDK_JNI)
|
|
|
|
|
|
|
|
|
|
namespace ZeroTier {
|
|
|
|
|
|
|
|
|
|
#include <jni.h>
|
|
|
|
|
|
|
|
|
|
JNIEXPORT int JNICALL Java_zerotier_ZeroTier_ztjni_1start(JNIEnv *env, jobject thisObj, jstring path) {
|
|
|
|
|
if(path) {
|
|
|
|
|
homeDir = env->GetStringUTFChars(path, NULL);
|
|
|
|
|
zts_start(homeDir.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Shuts down ZeroTier service and SOCKS5 Proxy server
|
|
|
|
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1stop(JNIEnv *env, jobject thisObj) {
|
|
|
|
|
if(zt1Service)
|
|
|
|
|
zts_stop();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-06 19:16:01 -07:00
|
|
|
// Returns whether the ZeroTier service is running
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT jboolean JNICALL Java_zerotier_ZeroTier_ztjni_1running(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj)
|
|
|
|
|
{
|
2017-05-04 13:06:39 -07:00
|
|
|
return zts_running();
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
// Returns path for ZT config/data files
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT jstring JNICALL Java_zerotier_ZeroTier_ztjni_1homepath(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj)
|
|
|
|
|
{
|
2017-05-04 13:06:39 -07:00
|
|
|
// TODO: fix, should copy into given arg
|
|
|
|
|
// return (*env).NewStringUTF(zts_get_homepath());
|
|
|
|
|
return (*env).NewStringUTF("");
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
// Join a network
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1join(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
|
|
|
{
|
2017-04-06 19:16:01 -07:00
|
|
|
const char *nwidstr;
|
|
|
|
|
if(nwid) {
|
|
|
|
|
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
2017-05-04 13:06:39 -07:00
|
|
|
zts_join(nwidstr);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Leave a network
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1leave(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
|
|
|
{
|
2017-04-06 19:16:01 -07:00
|
|
|
const char *nwidstr;
|
|
|
|
|
if(nwid) {
|
|
|
|
|
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
2017-05-04 13:06:39 -07:00
|
|
|
zts_leave(nwidstr);
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 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
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv4_1address(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
|
|
|
{
|
2017-04-06 19:16:01 -07:00
|
|
|
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
|
|
|
|
char address_string[32];
|
|
|
|
|
memset(address_string, 0, 32);
|
2017-05-04 13:06:39 -07:00
|
|
|
zts_get_ipv4_address(nwid_str, address_string, ZT_MAX_IPADDR_LEN);
|
2017-04-06 19:16:01 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv6_1address(
|
2017-04-07 17:56:05 -07:00
|
|
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
|
|
|
{
|
2017-04-06 19:16:01 -07:00
|
|
|
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
|
|
|
|
char address_string[32];
|
|
|
|
|
memset(address_string, 0, 32);
|
2017-05-04 13:06:39 -07:00
|
|
|
zts_get_ipv6_address(nwid_str, address_string, ZT_MAX_IPADDR_LEN);
|
2017-04-06 19:16:01 -07:00
|
|
|
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
|
2017-05-04 13:06:39 -07:00
|
|
|
JNIEXPORT jint Java_zerotier_ZeroTier_ztjni_1get_1device_1id()
|
2017-04-07 17:56:05 -07:00
|
|
|
{
|
2017-04-06 19:16:01 -07:00
|
|
|
return zts_get_device_id(NULL); // TODO
|
|
|
|
|
}
|
2017-05-04 13:06:39 -07:00
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags)
|
2017-04-07 17:56:05 -07:00
|
|
|
{
|
2017-05-04 13:06:39 -07:00
|
|
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
|
|
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
|
|
|
memcpy(bufp, body, len);
|
|
|
|
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
|
|
|
int written_bytes = zts_write(fd, body, len);
|
|
|
|
|
return written_bytes;
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
2017-05-04 13:06:39 -07:00
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1sendto(
|
|
|
|
|
JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr)
|
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
jclass cls = (*env).GetObjectClass( ztaddr);
|
|
|
|
|
jfieldID f = (*env).GetFieldID( cls, "port", "I");
|
|
|
|
|
addr.sin_port = htons((*env).GetIntField( ztaddr, f));
|
|
|
|
|
f = (*env).GetFieldID( cls, "_rawAddr", "J");
|
|
|
|
|
addr.sin_addr.s_addr = (*env).GetLongField( 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((_jbyteArray *)buf, 0);
|
|
|
|
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
|
|
|
memcpy(bufp, body, len);
|
|
|
|
|
(*env).ReleaseByteArrayElements((_jbyteArray *)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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1recvfrom(
|
|
|
|
|
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len, jint flags, jobject ztaddr)
|
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
jbyte *body = (*env).GetByteArrayElements( buf, 0);
|
|
|
|
|
unsigned char buffer[ZT_SDK_MTU];
|
|
|
|
|
int payload_offset = sizeof(int) + sizeof(struct sockaddr_storage);
|
|
|
|
|
int rxbytes = zts_recvfrom(fd, &buffer, len, flags, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr_storage));
|
|
|
|
|
if(rxbytes > 0)
|
|
|
|
|
memcpy(body, (jbyte*)buffer + payload_offset, rxbytes);
|
|
|
|
|
(*env).ReleaseByteArrayElements( buf, body, 0);
|
|
|
|
|
// Update fields of Java ZTAddress object
|
|
|
|
|
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 rxbytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len)
|
|
|
|
|
{
|
|
|
|
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
|
|
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
|
|
|
memcpy(bufp, body, len);
|
|
|
|
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
|
|
|
int written_bytes = zts_write(fd, body, len);
|
|
|
|
|
return written_bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len)
|
|
|
|
|
{
|
|
|
|
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
|
|
|
int read_bytes = read(fd, body, len);
|
|
|
|
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
|
|
|
return read_bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1setsockopt(
|
|
|
|
|
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) {
|
|
|
|
|
return zts_setsockopt(fd, level, optname, (const void*)optval, optlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockopt(JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jint optval, jint optlen) {
|
|
|
|
|
return zts_getsockopt(fd, level, optname, (void*)optval, (socklen_t *)optlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1socket(JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol) {
|
|
|
|
|
return zts_socket(family, type, protocol);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1connect(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) {
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
const char *str = (*env).GetStringUTFChars( addrstr, 0);
|
|
|
|
|
addr.sin_addr.s_addr = inet_addr(str);
|
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
addr.sin_port = htons( port );
|
|
|
|
|
(*env).ReleaseStringUTFChars( addrstr, str);
|
|
|
|
|
return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1bind(JNIEnv *env, jobject thisObj, jint fd, jstring addrstr, jint port) {
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
const char *str = (*env).GetStringUTFChars( 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( addrstr, str);
|
|
|
|
|
return zts_bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(__linux__)
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_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( 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
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_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, (socklen_t *)sizeof(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1listen(JNIEnv *env, jobject thisObj, jint fd, int backlog) {
|
|
|
|
|
return zts_listen(fd, backlog);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1close(JNIEnv *env, jobject thisObj, jint fd) {
|
|
|
|
|
return zts_close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) {
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
|
|
|
|
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 jint JNICALL Java_zerotier_ZeroTier_ztjni_1getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject ztaddr) {
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
|
|
|
|
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 jint JNICALL Java_zerotier_ZeroTier_ztjni_1fcntl(JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags) {
|
|
|
|
|
return zts_fcntl(fd,cmd,flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
#endif
|
|
|
|
|
|
2017-04-07 17:56:05 -07:00
|
|
|
/****************************************************************************/
|
|
|
|
|
/* SDK Socket API Helper functions --- DONT CALL THESE DIRECTLY */
|
|
|
|
|
/****************************************************************************/
|
2017-04-06 19:16:01 -07:00
|
|
|
|
|
|
|
|
// Starts a ZeroTier service in the background
|
2017-04-07 17:56:05 -07:00
|
|
|
void *_start_service(void *thread_id) {
|
2017-04-06 19:16:01 -07:00
|
|
|
|
2017-04-14 17:23:28 -07:00
|
|
|
DEBUG_INFO("homeDir=%s", ZeroTier::homeDir.c_str());
|
2017-04-06 19:16:01 -07:00
|
|
|
// Where network .conf files will be stored
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::netDir = ZeroTier::homeDir + "/networks.d";
|
2017-04-06 19:16:01 -07:00
|
|
|
zt1Service = (ZeroTier::OneService *)0;
|
|
|
|
|
|
|
|
|
|
// Construct path for network config and supporting service files
|
2017-04-14 17:23:28 -07:00
|
|
|
if (ZeroTier::homeDir.length()) {
|
|
|
|
|
std::vector<std::string> hpsp(ZeroTier::OSUtils::split(ZeroTier::homeDir.c_str(),
|
2017-04-07 17:56:05 -07:00
|
|
|
ZT_PATH_SEPARATOR_S,"",""));
|
2017-04-06 19:16:01 -07:00
|
|
|
std::string ptmp;
|
2017-04-14 17:23:28 -07:00
|
|
|
if (ZeroTier::homeDir[0] == ZT_PATH_SEPARATOR)
|
2017-04-06 19:16:01 -07:00
|
|
|
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;
|
|
|
|
|
}
|
2017-04-07 17:56:05 -07:00
|
|
|
// rpc dir
|
2017-04-14 17:23:28 -07:00
|
|
|
if(!ZeroTier::OSUtils::mkdir(ZeroTier::homeDir + "/" + ZT_SDK_RPC_DIR_PREFIX)) {
|
2017-04-07 17:56:05 -07:00
|
|
|
DEBUG_ERROR("unable to create dir: " ZT_SDK_RPC_DIR_PREFIX);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2017-04-06 19:16:01 -07:00
|
|
|
|
|
|
|
|
// Generate random port for new service instance
|
|
|
|
|
unsigned int randp = 0;
|
|
|
|
|
ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
|
2017-05-01 18:18:20 -07:00
|
|
|
// TODO: Better port random range selection
|
2017-04-20 13:39:46 -07:00
|
|
|
int servicePort = 9000 + (randp % 1000);
|
2017-04-06 19:16:01 -07:00
|
|
|
|
|
|
|
|
for(;;) {
|
2017-04-14 17:23:28 -07:00
|
|
|
zt1Service = ZeroTier::OneService::newInstance(ZeroTier::homeDir.c_str(),servicePort);
|
2017-04-06 19:16:01 -07:00
|
|
|
switch(zt1Service->run()) {
|
2017-04-07 17:56:05 -07:00
|
|
|
case ZeroTier::OneService::ONE_STILL_RUNNING:
|
2017-04-06 19:16:01 -07:00
|
|
|
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;
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::OSUtils::readFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
|
2017-04-07 17:56:05 -07:00
|
|
|
+ "identity.secret").c_str(),oldid);
|
2017-04-06 19:16:01 -07:00
|
|
|
if (oldid.length()) {
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::OSUtils::writeFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
|
2017-04-07 17:56:05 -07:00
|
|
|
+ "identity.secret.saved_after_collision").c_str(),oldid);
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
|
2017-04-07 17:56:05 -07:00
|
|
|
+ "identity.secret").c_str());
|
2017-04-14 17:23:28 -07:00
|
|
|
ZeroTier::OSUtils::rm((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S
|
2017-04-07 17:56:05 -07:00
|
|
|
+ "identity.public").c_str());
|
2017-04-06 19:16:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue; // restart!
|
|
|
|
|
}
|
|
|
|
|
break; // terminate loop -- normally we don't keep restarting
|
|
|
|
|
}
|
|
|
|
|
delete zt1Service;
|
|
|
|
|
zt1Service = (ZeroTier::OneService *)0;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|